TypeScript 中的类型谓词
Type predicates in TypeScript
这是 TypeScript 中缺少的功能还是经过深思熟虑的问题,如果条件逻辑被包装到一个单独的函数中,TS 编译器无法推断(然后缩小)参数的类型?我想到的是 TS 编译器在这种情况下给我的错误:
function isString(s) {
return typeof s === 'string';
}
function toUpperCase(x: unknown) {
if(isString(x)) {
x.toUpperCase(); // ⚡️ x is still of type unknown
}
}
但是,如果我去掉 isString
函数并在 if
语句中内联它的逻辑,那么 TS 编译器就会很好地识别该类型。
我知道我可以使用 as string
转换类型或使用类型谓词并在 isString
函数中使用 is string
类型注释。但是我刚开始思考——为什么TS不能缩小x
.
的类型
实现这一点的一种方法是,如果编译器在执行控制流分析时内联了一些函数调用,这意味着:
function toUpperCase(x: unknown) {
if (isString(x)) {
x.toUpperCase();
}
}
需要像 isString()
的正文这样展开来分析:
function toUpperCase(x: unknown) {
if (typeof x === "string") {
x.toUpperCase();
}
}
GitHub 中谈论这个的规范问题是 microsoft/TypeScript#9998。该期中提出的问题是 "When a function is invoked, what should we assume its side effects are?" 并且似乎没有完美的答案。据说所有函数调用的全内联解决方案"wouldn't be even remotely practical"。 是否可以 完成浅内联,使 isString()
的行为如您所愿,而不会完全拖慢编译器?可能吧,但值得吗?不确定。看起来那里没有取得太大进展;如果您对此有足够强烈的感觉并且有一些令人信服的想法,您可以为 GitHub 问题做出贡献。
另一种工作方式是,如果编译器自动推断类型谓词 return 类型的正确类型 boolean
-returning 函数,这意味着:
function isString(s: unknown) {
return typeof s === "string";
}
需要这样推断:
function isString(s: unknown): s is string {
return typeof s === "string";
}
GitHub 中谈论这个的规范问题是 microsoft/TypeScript#16069. A previous version of this was declined as being too complex 因为编译器能够分析每个 boolean-returning 函数和图形是不切实际的out 是否对其 return 类型有任何类似类型谓词的含义。不过,#16069 仍然开放,大概是为了采摘 "simple" 函数(如 x => typeof x === "string"
)的唾手可得的果实。同样,目前尚不清楚那里是否取得了任何进展,因此如果您对此有足够强烈的感觉并有一些令人信服的想法,您可以为 GitHub 问题做出贡献。
但如果我是你,在这两种情况下我都不会屏住呼吸。 TS3.6 的惯用解决方案是将 isString()
注释为用户定义的类型保护 returning s is string
并继续其他事情。
好的,希望对你有帮助。祝你好运!
这是 TypeScript 中缺少的功能还是经过深思熟虑的问题,如果条件逻辑被包装到一个单独的函数中,TS 编译器无法推断(然后缩小)参数的类型?我想到的是 TS 编译器在这种情况下给我的错误:
function isString(s) {
return typeof s === 'string';
}
function toUpperCase(x: unknown) {
if(isString(x)) {
x.toUpperCase(); // ⚡️ x is still of type unknown
}
}
但是,如果我去掉 isString
函数并在 if
语句中内联它的逻辑,那么 TS 编译器就会很好地识别该类型。
我知道我可以使用 as string
转换类型或使用类型谓词并在 isString
函数中使用 is string
类型注释。但是我刚开始思考——为什么TS不能缩小x
.
实现这一点的一种方法是,如果编译器在执行控制流分析时内联了一些函数调用,这意味着:
function toUpperCase(x: unknown) {
if (isString(x)) {
x.toUpperCase();
}
}
需要像 isString()
的正文这样展开来分析:
function toUpperCase(x: unknown) {
if (typeof x === "string") {
x.toUpperCase();
}
}
GitHub 中谈论这个的规范问题是 microsoft/TypeScript#9998。该期中提出的问题是 "When a function is invoked, what should we assume its side effects are?" 并且似乎没有完美的答案。据说所有函数调用的全内联解决方案"wouldn't be even remotely practical"。 是否可以 完成浅内联,使 isString()
的行为如您所愿,而不会完全拖慢编译器?可能吧,但值得吗?不确定。看起来那里没有取得太大进展;如果您对此有足够强烈的感觉并且有一些令人信服的想法,您可以为 GitHub 问题做出贡献。
另一种工作方式是,如果编译器自动推断类型谓词 return 类型的正确类型 boolean
-returning 函数,这意味着:
function isString(s: unknown) {
return typeof s === "string";
}
需要这样推断:
function isString(s: unknown): s is string {
return typeof s === "string";
}
GitHub 中谈论这个的规范问题是 microsoft/TypeScript#16069. A previous version of this was declined as being too complex 因为编译器能够分析每个 boolean-returning 函数和图形是不切实际的out 是否对其 return 类型有任何类似类型谓词的含义。不过,#16069 仍然开放,大概是为了采摘 "simple" 函数(如 x => typeof x === "string"
)的唾手可得的果实。同样,目前尚不清楚那里是否取得了任何进展,因此如果您对此有足够强烈的感觉并有一些令人信服的想法,您可以为 GitHub 问题做出贡献。
但如果我是你,在这两种情况下我都不会屏住呼吸。 TS3.6 的惯用解决方案是将 isString()
注释为用户定义的类型保护 returning s is string
并继续其他事情。
好的,希望对你有帮助。祝你好运!