首页 > 解决方案 > 打字稿错误 - 可以用不同的约束子类型实例化

问题描述

打字稿沙箱。

有时基于代码,我知道返回值是什么,并希望使用以下方法指定它:

getSmth<string>(1)

并不是

getSmth(1) as string

但不确定如何正确执行


  1. 问题。如果我正确扩展和返回,为什么会出现错误?
Type 'null' is not assignable to type 'T'.
  'null' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'string | null'.(2322)

例子

const getName = (id: number) : string | null => null

const getSmth = <T extends string | null = string | null>(id: number | null): T => {
  if (!id) {
    return null;
  }
  return getName(id);
};

const x1 = getSmth(1) // should be string | null
const x2 = getSmth<null>(1) // should be null
const x3 = getSmth<string>(1) // should be string

  1. 问题。为什么会出现这种断言?
const getSmth2 = <T extends string | null = string | null>(id: number | null): T => {
  if (!id) {
    return null as T;
  }
  return getName(id) as T;
};

const y1: string = getSmth2(1) // why getSmth2 asserts to string when return type should bestring | null

标签: typescript

解决方案


如果我正确扩展和返回,为什么会出现错误?

T由于约束,不保证可以为空。例如,string扩展string | null

// true
type X = string extends string | null ? true : false;

因此,虽然您给出的默认值T是可以为空的,但编译器无法确保这对于所有可能T的 s 都是正确的。事实上,这正是你正在尝试做的事情:通过string. 但是一旦T = string,返回null将不再有效。

您可以在实现中键入断言以使其工作。不过,这只会让编译器关闭它确实正确的东西,但如果这是你想要做的:

const getSmth = <T extends string | null = string | null>(id: number | null): T => {
  if (!id) {
    return null as T;
  }

  return getName(id) as T;
};
  1. 问题。为什么会出现这种断言?

本质上,这是同一个问题。这里补充一点,编译器使用左边声明的类型来推断泛型类型参数:

// T inferred to be string
const y1: string = getSmth2(1);

// T is inferred to be string | null
const y2: string | null = getSmth2(1);

您期望T使用默认值,在这种情况下会发生这种情况:

// string | null
const y3 = getSmth2(1);

推荐阅读