TypeScript 类型歧视在泛型和Map类型值上被破坏,当strictNullChecks为false时,

iqjalb3h  于 6个月前  发布在  TypeScript
关注(0)|答案(3)|浏览(54)

在具有泛型类型上的Map类型的函数中,遇到了一个类型歧视的bug。我尽量使复现变得简单。

TypeScript 版本: 4.1.0-beta
搜索词:

区分,泛型,Map类型,严格空值检查关闭

代码

type Mapping<T> = { [key in keyof T]?: string | (() => string) };

function foo<T>(mapping: Mapping<T>) {
    const results: {[key: string]: string} = {};
    for (const key in mapping) {
      const valueTransform = mapping[key];
      if (typeof valueTransform === 'function') {
        results[key] = valueTransform(); //! This expression is not callable...
      } else if(typeof valueTransform === 'string') {
        results[key] = valueTransform;
      }
    }
    return results;
}

预期行为:
实际行为:

strictNullChecks:false 我得到了以下错误:

This expression is not callable.
  Not all constituents of type 'string | (() => string)' are callable.
    Type 'string' has no call signatures.

如果你把它改回 true ,它将按预期工作。似乎与泛型和Map类型的组合有关,如果直接改为引用 Foo ,代码将正常编译。
type Mapping<T> = { [key in keyof Foo]?: string | (() => string) };
此外,区分似乎只在 typeof valueTransform === 'function' 上失效。

**Playground 链接:**Playground 链接
相关问题:

#27470

ykejflvf

ykejflvf1#

问题可以通过以下示例再现:

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

错误如下:

This expression is not callable. Not all constituents of type '(() => T) | (T & Function)' are callable. 
Type 'T & Function' has no call signatures.

将类型保护从 typeof value === 'function' 更改为 value instanceof Function 后,问题得到解决。

bksxznpy

bksxznpy2#

在通用情况下,我认为 insatnceof 的行为是错误的,这应该是一个错误。如果 T(a: string) => string,那么类型保护不会将 T 从 true 分支中排除:

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

runIfFunction<(a: string) => string>((a: string) => a.toLocaleLowerCase())

Playground Link

nfs0ujit

nfs0ujit3#

另一个示例:

type A0<A0T> = Exclude<A0T, Function>;
type A1<A1T> = Exclude<A1T, Function> | Function;

function f<XF>(x: XF): void {
  type AF0 = A0<XF>
  type AF1 = A1<XF>

  const y0 = {} as AF0;
  const y1 = {} as AF1;

  const z0 = typeof y0 === 'function' ? y0() : undefined;
  const z1 = typeof y1 === 'function' ? y1() : undefined;
  /*                                   ^^^^^
This expression is not callable.
No constituent of type 'Function | (Exclude<XF, Function> & Function)' is callable.(2349)
*/

  const r = typeof y1 === 'function' ? y1 : null as never;
  type R = typeof r; // type R = Function
}

播放

相关问题