Create React App 如何允许 Array.prototype.at() 而 TypeScript 不允许?

Posted

技术标签:

【中文标题】Create React App 如何允许 Array.prototype.at() 而 TypeScript 不允许?【英文标题】:How does Create React App allow for Array.prototype.at() while it's not allowed by TypeScript? 【发布时间】:2021-12-29 07:29:20 【问题描述】:

在我们的 CRA 项目中,我们有这样的代码:

const patTable = tables['pat'].at(0);

Array.prototype.at() 功能是一个新功能,在旧版浏览器(例如 Chrome 89)中不可用。但由于某种原因,CRA 甚至没有发出警告或错误消息,并且很容易接受它。它还没有填充 .at() 函数,现在它正在破坏旧浏览器中的应用程序。

WebStorm 显示的推断类型为Table | undefined(由于@types/node 16.x,但我不确定)。

还要注意 TypeScript 还不支持.at(),例如:

function foo(values: string[]) 
  const value = values.at(0);

引发错误:Property 'at' does not exist on type 'string[]'.(2339)

Sandbox

您是否有任何想法,TS 检查、linting 或构建都没有检测到问题怎么可能?

TS版本为:4.3.5 tsconfig.json 是:


  "compilerOptions": 
    "target": "es6",
    "lib": ["dom", "dom.iterable", "esnext"],
    "sourceMap": true,
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "noImplicitAny": true,
    "noImplicitThis": true,
    "strictNullChecks": true,
    "jsx": "react-jsx",
    "baseUrl": "src",
    "noFallthroughCasesInSwitch": true
  ,
  "include": ["src", "types/global-fetch.d.ts"]


【问题讨论】:

"lib": ["dom", "dom.iterable", "esnext"], 注意esnext 不,它不影响它。在我们的项目中,唯一受esnext 影响的行是someString.replaceAll(...)。 100%。 @Onkeltem - 虽然它现在不会,但它会,所以你需要考虑"esnext"是否真的适合这个项目。 谢谢@T.J.Crowder,我明白了。是的,我宁愿附上一些特定的 polyfill。例如:仅限我的replaceAll() 【参考方案1】:

即使您正在处理面向浏览器的代码,它也可能是从 Node.js 类型中提取出来的。 Node.js 的类型包括RelativeIndexable——来自@types/node/globals.d.ts

//#region ArrayLike.at()
interface RelativeIndexable<T> 
    /**
     * Takes an integer value and returns the item at that index,
     * allowing for positive and negative integers.
     * Negative integers count back from the last item in the array.
     */
    at(index: number): T | undefined;

interface String extends RelativeIndexable<string> 
interface Array<T> extends RelativeIndexable<T> 
interface Int8Array extends RelativeIndexable<number> 
interface Uint8Array extends RelativeIndexable<number> 
interface Uint8ClampedArray extends RelativeIndexable<number> 
interface Int16Array extends RelativeIndexable<number> 
interface Uint16Array extends RelativeIndexable<number> 
interface Int32Array extends RelativeIndexable<number> 
interface Uint32Array extends RelativeIndexable<number> 
interface Float32Array extends RelativeIndexable<number> 
interface Float64Array extends RelativeIndexable<number> 
interface BigInt64Array extends RelativeIndexable<bigint> 
interface BigUint64Array extends RelativeIndexable<bigint> 
//#endregion ArrayLike.at() end

我在使用 Node 构建的项目中使用 Node.js 类型时遇到了这个问题,即使它们是为浏览器构建的。 (我主要是在setTimeout 的返回值上遇到它。)我刚刚检查了一个项目,果然,它很高兴使用at(并将其解析为上述问题),即使我从未明确表示过在项目中安装了@types/node

我不使用 WebStorm,但在 VSCode 中,您可以通过将光标放在 at 上并按 F12 以“转到定义”来检查 at 的类型来自何处。大概 WebStorm 也有类似的东西。

我认为这是有用的信息,并且比评论更适合作为答案,但它确实提出了一个问题“那么我该如何防止这种情况发生?”我不得不承认我现在无法回答。我已将答案标记为 CW,希望有人可以更新以解决它。

【讨论】:

还是谢谢你!我确认我在node_modules/@types/node 下具有完全相同的 typedef - 即节点(v.16)。 IDE 的行为似乎相似 - WS 也从那里使用类型。但是我无法回答 CRA 的 webpack 如何“神奇地”使用这个.at()。看起来有一个临时的 polyfill,它在类型检查时使用,然后在构建时搁置(因此进入构建的应用程序时不会受到影响)。 在构建过程中代码不会运行,对吧?这是客户端代码。所以没有临时的 polyfill 或任何东西,只有 @types/node 类型让 TypeScript 认为 at 会在运行时出现,而它不会(必然)存在。 唷,它是多么复杂。那些节点 16 类型通过依赖项意外出现。那么绝对值得禁用这种自动类型......采集。我希望我可以在tsconfig.json 中使用"exclude": ["node_modules/@types/node/globals.d.ts"] 来做到这一点,但是......不。这不是办法。毕竟为什么要在构建浏览器应用程序时包含 node 类型?

以上是关于Create React App 如何允许 Array.prototype.at() 而 TypeScript 不允许?的主要内容,如果未能解决你的问题,请参考以下文章

sh 用于将工作证书链接到create-react-app的脚本。允许您使用create-react-app和有效的SSL证书。

为啥我收到此错误 - 错误:EPERM:不允许操作,找不到 mkdir 'C:\Users\Aniket' 命令:create-react-app

如何开发由Create-React-App 引导的应用

是否可以将装饰器与 create-react-app 一起使用?

create-react-app:如何在 React 渲染之前加载 html

如何在 create-react-app 中注入没有 REACT_APP 前缀的 dotenv 变量?