【问题标题】:How does Create React App allow for Array.prototype.at() while it's not allowed by TypeScript?Create React App 如何允许 Array.prototype.at() 而 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()

标签: reactjs typescript create-react-app tsconfig


【解决方案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 类型?
猜你喜欢
  • 2017-11-09
  • 2021-03-06
  • 2020-11-14
  • 2022-01-09
  • 1970-01-01
  • 2016-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多