为什么即使在我确认我正在从非空数组中删除一个元素之后,Typescript 仍然警告我pop()可能会返回undefined?
type Person = {
name: string;
};
const people: Person[] = [{ name: 'Sandra' }];
if (people.length) {
const { name } = people.pop();
// TS Error: Property 'name' does not exist on type 'Person | undefined'.
}
Run Code Online (Sandbox Code Playgroud)
即使我做出更明确的保证,我也会得到同样的错误:
if (people.length > 0 && people[people.length - 1] !== undefined){
const { name } = people.pop();
// TS Error: Property 'name' does not exist on type 'Person | undefined'.
}
Run Code Online (Sandbox Code Playgroud)
有关规范答案,请参阅microsoft/TypeScript#30406。
对于“为什么编译器认为即使我检查数组也pop()可能返回”的问题,简短的回答是“因为 TypeScript 标准库对返回方法的调用签名”:undefinedlengthpop()Array<T>T | undefined
interface Array<T> {
// ... elided
pop(): T | undefined;
// ... elided
}
Run Code Online (Sandbox Code Playgroud)
因此,无论何时调用pop()数组,返回值的类型都将包括undefined.
逻辑下一个问题是:“为什么他们不把更好的通话签名这回T如果length不为零,且undefined如果length是零?” 这个问题的答案是是“因为检查length一般的数组类型的属性不会改变明显类型的数组,因此呼叫签名可以不出有什么区别。”
例如,您可以添加一些这样的调用签名:
interface Array<T> {
pop(this: { length: 0 }): undefined;
pop(this: { 0: T }): T;
}
Run Code Online (Sandbox Code Playgroud)
通过使用this参数,每个调用签名只会在调用方法的数组与指定类型匹配时才会被选中。如果数组有一个lengthof 0,则返回undefined。如果数组T在 key 处有一个 type 元素0,则返回T。
这将适用于长度固定且元素索引已知的元组类型:
declare const u: [];
const a = u.pop(); // undefined
declare const v: [1, 2];
const b = v.pop(); // 1 | 2
Run Code Online (Sandbox Code Playgroud)
但是当然,调用pop()元组是一个坏主意,而不是您可能想要的那种东西。如果您有一个可变长度数组并调用pop()它,则不会选择任何调用签名并且您回退到内置的T | undefined,即使您尝试检查length:
const w = Math.random() < 0.5 ? [] : ["a"] // string[]
if (w.length) {
w.pop().toUpperCase(); // error! Object is possibly undefined
}
Run Code Online (Sandbox Code Playgroud)
问题是lengthan的属性Array<T>是 type number,并且没有number要缩小w.length到的“非零”类型。为了支持这种事情,您需要诸如不属于 TypeScript 的否定类型之类的东西。有可能通过足够的编译器工作,有人可以为 TypeScript 中的数组提供足够的结构,这样真实性检查w.length就会将数组的类型缩小到您可以调用的范围pop(),而不必担心undefined退出。
但是它会给编译器和支持这个用例的语言增加大量的复杂性。收益不可能超过成本。
在没有这个的情况下,你可以更容易地跳过length检查并调用pop(),检查它是否undefined存在。这对您来说是相同的工作量,因为它只是将检查从调用之前移到调用之后,并且它使编译器的工作更加简单。
此处发布的其他答案建议了此方法和其他解决方法,因此我不会深入研究它们。我的主要观点是语言没有配备允许length检查影响pop(). 或者,正如@RyanCavanaugh(TS 的开发负责人)在 microsoft/TypeScript#30406 中提到的那样,
这不是我们能够追踪的
那好吧!
| 归档时间: |
|
| 查看次数: |
769 次 |
| 最近记录: |