gpt4 book ai didi

TypeScript 联合类型 - 仅在函数调用时出错

转载 作者:行者123 更新时间:2023-12-05 02:31:02 25 4
gpt4 key购买 nike

在 TypeScript 中使用联合类型时,我偶然发现了一个奇怪的行为。当传递一个函数的引用时,不调用它,没有类型错误:

type A = boolean;
type B = string;
type C = number;
type BC = B | C;

interface Props { onChange(expr: A | BC): void }

const SomeFunction = (_props: Props) => {}
const handler = (el: A | B) => { console.log(el) }

SomeFunction({onChange: handler}) // no error here

SomeFunction({onChange: e => handler(e)}) // <- TS Error: Argument of type 'boolean | BC' is not assignable to parameter of type 'string | boolean'.

我能找到的唯一解释是 improved behavior for calling union types在 TypeScript 3.3 中。

我很好奇为什么调用SomeFunction({onChange: handler})时没有报错——是不是联合类型之间存在重叠?

link to typescript playground

最佳答案

区别在于handler是一个非方法函数,而onChange是在Props中声明为一个方法。当你有 the --strictFunctionTypes compiler option启用(属于 the --strict suite of compiler functionality 的一部分),非方法函数的参数检查更严格。

为了类型安全,函数的参数应该反变检查,这在this q/a中有描述。 ,但简而言之,可以安全地缩小但不能扩大函数参数。由于 Expr | PrimitiveExpr | 宽StringOrBool,将 handler 视为 onChange 是不安全的,如下所示,当您添加一些功能时:

const SomeFunction = (_props: Props) => { _props.onChange(3) }

const handler = (el: Expr | StringOrBool) => {
if ((typeof el !== "boolean") && (typeof el !== "object")) {
console.log(el.toUpperCase()); // has to be a string, right?
}
console.log(el)
}

SomeFunction({ onChange: handler }) // runtime error: el.toUpperCase is not a function

handler 函数假定非 bool 非对象参数必须是字符串,但是 SomeFunction 调用 _props.onChange()有一个号码。糟糕!

所以在这一点上应该很清楚,如果我们只关心类型安全,那么两个 SomeFunction 调用都应该有错误。实际上,如果我们重写 Props 以对 onChange 使用非方法语法:

interface Props {
onChange: (expr: Expr | Primitive) => void // call expression, not method
}

然后我们确实看到了两个错误:

SomeFunction({ onChange: handler }) // error! 
SomeFunction({ onChange: e => handler(e) }) // error!

但是方法(实际上所有未启用 --strictFunctionTypes 的函数)都允许安全缩小(逆变)和不安全扩大(协变)。也就是说,方法参数是双变检查的。为什么?好吧,事实证明,尽管这是不安全的,但它非常有用。你可以阅读this FAQ entrythis doc有关详细信息,但简而言之,它支持一些常见的编码实践(如事件处理)。人们喜欢狗[]当作动物[]对待,即使从技术上讲它是不安全的。如果方法被安全对待,那么 Animal[]push() 方法的存在将阻止任何人使用 Dog[] 作为一个 Animal[]。参见 this Q/A获取更多信息。

因为我们可以同时使用方法语法和箭头函数语法,所以如果需要,我们可以同时使用这两种语法;每当您关心函数参数的类型安全时,请远离方法语法。

Playground link to code

关于TypeScript 联合类型 - 仅在函数调用时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71708844/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com