繁体   English   中英

从类型的默认参数进行 TypeScript 类型推断

[英]TypeScript type inference from default parameter of type

给出以下示例:

interface Foo {
  name: string;
}

interface Bar extends Foo {
  displayName: string;
}

const foo: Foo = { name: "foo" };
const bar: Bar = { name: "bar", displayName: "dn" };

const getName = <T extends Foo>(obj: T = foo): string => {
  return obj.name;
};

getName(foo); // Ok
getName(bar); // Ok

obj: T = foo导致错误。 即使T extends Foo ,这也不被接受。 为什么会这样,有什么解决方法?

例子

您的getName函数不需要泛型,并且可以对输入参数obj使用Foo类型注释,即:

const getName = (obj: Foo = foo): string => {
  return obj.name;
};

尽管您将类型Foo分配给obj它也适用于getName(bar); 因为Bar extends Foo 换句话说:由于 TypeScript 知道FooBar更具体,因此getName函数将接受Bar类型的任何元素。

您不需要泛型,因为您不想将函数的不同部分相互关联。 如果您想将输入参数与输出参数相关联,则可以有效使用泛型。

请参阅您的代码的此TS Playground

另请参阅有关您遇到的错误的相关问题,即

Type 'Foo' is not assignable to type 'T'.
  'Foo' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Foo'.(2322)

问题是foo不是T类型,假设您想使用接口Bar实例化泛型:

const getName = (obj: Bar = foo): string => {
  return obj.name;
};

您可以看到foo不是Bar (缺少displayName属性)并且您不能将其分配给Bar类型的变量。

您现在有三个选择:

  1. 强制foo用作泛型T : <T extends Foo>(obj: T = foo as T): string => ... 但这是您能做的最糟糕的选择(可能导致意外结果/错误)。

  2. 重载您的函数以匹配您的通用规范。 如果您需要返回(并实际使用)您的通用实例,这很有用:

const getName: {
  // when you specify a generic on the function
  // you will use this overload
  <T extends Foo>(obj: T): T;

  // when you omit the generic this will be the overload
  // chosen by the compiler (with an optional parameter)
  (obj?: Foo): Foo;
}
= (obj: Foo = foo): string => ...;
  1. 请注意,您的函数根本不使用泛型并将参数作为简单的Foo : (obj: Foo = foo): string => ...传递。 在您的情况下,这应该是最好的

暂无
暂无

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

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