简体   繁体   English

TypeScript 函数在不期望的情况下通过类型检查

[英]TypeScript function passes type check when not expected to

I have a function identityOrCall that either calls the function given to it, or returns the value.我有一个函数identityOrCall要么调用给它的函数,要么返回值。 value is a generic type. value是一个泛型类型。

function identityOrCall <T>(value: T): T {
  if (typeof value === 'function')
    return value()
  else
    return value
}

identityOrCall(() => 'x') // -> 'x'

The line identityOrCall(() => 'x') appears to pass the compiler's type checking.identityOrCall(() => 'x')似乎通过了编译器的类型检查。

Why?为什么? Shouldn't it give an error?它不应该给出错误吗?

If identityOrCall is passed a function, I would expect the generic type T to be set to Function and that identityOrCall should return a Function type.如果向identityOrCall传递一个函数,我希望将泛型类型T设置为Function并且该identityOrCall应返回一个Function类型。

Instead I'm able to pass a Function type as an argument and have identityOrCall return a string type.相反,我可以将Function类型作为参数传递,并让identityOrCall返回一个string类型。

Why is this?为什么是这样? It appears inconsistent to me, but I must be missing something.这对我来说似乎不一致,但我一定错过了一些东西。

The problem is that, since the function return type is not noted anywhere, TypeScript takes its type to be any .问题是,由于函数返回类型没有在任何地方注明,TypeScript 将其类型设为any any is not type-safe; any不是类型安全的; it's assignable to anything.它可以分配给任何东西。 Here, TS extracts T from the any return value (since any can be narrowed down to T).在这里,TS 从any返回值中提取T (因为any可以缩小到 T)。

Best to avoid types of any whenever possible.最好尽可能避免any类型。 I like using TSLint's no-unsafe-any which forbids this sort of thing.我喜欢使用 TSLint 的no-unsafe-any来禁止这种事情。

For similar reasons, the following does not throw a TypeScript error (and is prohibited using the above linting rule), even though it's clearly unsafe:出于类似的原因,以下内容不会引发 TypeScript 错误(并且禁止使用上述 linting 规则),即使它显然是不安全的:

declare const fn: () => any;
function identityOrCall<T>(value: T): T {
    return fn();
}

const result = identityOrCall(() => 'x') // -> 'x'
// result is typed as: () => 'x'. Huh?

If the goal is to have a method behave differently based on the parameters I think the easiest way is to specify overloads如果目标是让方法根据参数表现不同,我认为最简单的方法是指定重载

function identityOrCall<T>(value: () => T): T;
function identityOrCall<T>(value: T): T;

function identityOrCall <T>(value: () => T|T): T {
  if (typeof value === 'function')
    return value()
  else
    return value
}

const result = identityOrCall(() => 'x') // first overload
const result2 = identityOrCall('x') // second overload

result.split(' ');  // No error
result2.split(' '); // No error
result(); // error not callable

When calling the method TS will resolve the signature by going through the overloads until it finds one which matches (meaning order of defining overloads matters here).调用方法时,TS 将通过重载解析签名,直到找到匹配的一个(这意味着定义重载的顺序在这里很重要)。

Playground link 游乐场链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM