这在TypeScript 4.0.2中。类型系统可以从下面示例中的类型签名推断出一些值。我很困惑,为什么它不能推断出const b中最后一个元素的具体值。
有人能解释为什么,以及我如何写一个类型的签名,可以吗?
declare function identityA<T extends string[]>(p: readonly [...T]): T
declare function identityB<T extends any[]>(p: readonly [...T]): [...T]
const a = identityA(['r', 's']) // ['r', 's']
const b = identityB([...a, 3]) // ['r', 's', number]发布于 2020-09-25 02:23:39
TypeScript的类型推断使用各种启发式方法来确定何时扩大文字类型,以及何时使它们尽可能狭窄。例如,当你写
let s = ""; // string
let n = 0; // number
let b = true; // boolean变量s、n和b的类型分别扩展为string、number和boolean。假设是,由于let声明允许您重新分配值,所以您可能希望这样做。另一方面,当你写
const sC = ""; // ""
const nC = 0; // 0
const bC = true; // true变量sC、nC和bC的类型分别保持为""、0和true。假设因为不能更改这些值,所以没有理由允许类型中的单个值更多。
对于类型参数,如T在identityA()和identityB()函数中,编译器会执行其他操作。在微软/打字稿#10676中提到了这一点
在调用表达式的类型参数推断期间,如果(.)
T没有约束,或者它的约束不包括原语或文字类型,则将类型参数T的推断类型拓宽为其扩大的文字类型
在……里面
declare function identityA<T extends string[]>(p: readonly [...T]): T类型参数T有一个包含基本string类型的约束,因此T不会从["r", "s"]扩展到[string, string]。另一方面,在
declare function identityB<T extends any[]>(p: readonly [...T]): [...T]类型参数T的约束不包括任何文字或原始类型,因此T将从(比方说) [3]扩展到[number],或者由于"r"和"s"类型已经从以前的推断中没有扩展,T将从["r", "s", 3]扩展到["r", "s", number]。
这很让人困惑对吧?没关系,通过在您的多元元组类型参数类型中使用p [...T],您将提示编译器您希望推断元组类型 for T,而不仅仅是数组类型。
所以这就是它发生的原因。你能做些什么来修复它?
如果您控制了调用站点,您可以使用断言显式地要求编译器为您传递的内容推断最窄的类型。这发生在T推断之前:
const iBAsConst = identityB([...iA, 3] as const) // ['r', 's', 3]但是,您询问了如何更改签名以将identityB()的类型参数转换为文字偏好推理工具。您可以通过将any[]更改为包含原语的内容来做到这一点。例如:
type Narrowable = string | number | boolean | symbol |
object | undefined | void | null | {};
declare function identityC<T extends Narrowable[]>(p: readonly [...T]): [...T]
const iC = identityC(["r", "s", 3]); // ['r', 's', 3] 几乎任何东西都可以分配给Narrowable,就像一个奇怪的any或unknown,它也可以作为一个保持-这个-狭窄的提示。
万岁对吧?
如果这一切在你看来都是邪恶的魔法,我同意。不久前,我打开微软/打字稿#30680请求一些语法,以显式地请求函数的签名端的"as const"-like行为。然后你就可以写些东西
// don't try this, it won't work:
declare function identityB<T extends any[] as const>(p: readonly [...T]): [...T];才能达到同样的效果。唉,这只是今天(2020-09-24)的一个建议,所以现在你必须继续练习黑暗艺术,才能得到你想要的推论。
发布于 2020-09-25 01:33:44
如果将参数标记为identityB as const,TS可以将元组参数中的项的类型缩小到它们的文字类型。否则,它只使用typeof --最后一个参数。
declare function identityA<T extends string[]>(p: readonly [...T]): T
declare function identityB<T extends any[]>(p: readonly [...T]): [...T]
const a = identityA(['r', 's']) // ['r', 's']
const b = identityB([...a, 3] as const) // ['r', 's', 3] https://stackoverflow.com/questions/64056538
复制相似问题