typescript - 了解 TypeScript 中的通用约束扩展

标签 typescript generics

我正在尝试创建一个通用函数,它接受基类的子类型,并返回解析为指定类的实例的 promise 。这个例子展示了我想要实现的目标:

class foo {}
class bar extends foo {}
const someBar = new bar();
function foobar<T extends foo>(): Promise<T> {
  return new Promise<T>(resolve => resolve(someBar)); // this doesn't compile
}

我意识到 TypeScript 使用结构类型,因此在这个简单的示例中它将接受 T 的任何类型。但我不确定为什么它不允许我返回 someBar 的值。

有办法实现我在这里想做的事情吗?谢谢!

我得到的编译器错误是:

const someBar: bar
Argument of type 'bar' is not assignable to parameter of type 'T | PromiseLike<T> | undefined'.
  Property 'then' is missing in type 'bar' but required in type 'PromiseLike<T>'.ts(2345)
lib.es5.d.ts(1393, 5): 'then' is declared here.

更新

根据请求,这里有一些关于我想要完成的任务的附加信息。这段代码编译得很好(我已经向 foo 和 bar 添加了函数,只是为了在结构上区分它们):

class foo {
  f() {}
}
class bar extends foo {
  b() {}
}
const someBar = new bar();
function foobar(): Promise<foo> {
  return new Promise<foo>(resolve => resolve(someBar));
}
foobar().then(result => {
  const myBar: bar = result as bar;
  console.log(myBar);
});

我试图避免需要向下转换 promise 的多态结果 - const myBar: bar = result as bar,如下所示:

class foo {
  f() {}
}
class bar extends foo {
  b() {}
}
const someBar = new bar();
function foobar<T extends foo>(): Promise<T> {
  return new Promise<T>(resolve => resolve(someBar));
}
foobar<bar>().then(result => {
  const myBar: bar = result;
  console.log(myBar);
});

TS 正确推断结果是一个 bar,但它不允许我在函数中返回 someBar。

我已经能够在我的通用类方法处理 this 的类中使用多态 this 来实现此目的 - 但这里我不在一个类中.

更新2

实际上,这不需要 promise 来说明我在做什么。在这里,我进一步简化了(并省略了 foo 和 bar 的定义,因为它没有改变):

function foobar<T extends Foo>(): T {
  return someBar;
}
const mybar: Bar = foobar<Bar>();

而且,这就是我在“纯 JavaScript”中所做的事情:

var someBar = new bar();
function foobar() {
  return someBar;
}
var myBar = foobar();

如你所见,我所做的事情很微不足道。我只是想在不向下转型的情况下进行多态类型检查。

最佳答案

您提供的代码不是通用函数,因此您尝试将其输入为一个函数时走错了路。

通用函数是一种需要处理多种数据类型的函数,同时仍然能够指定函数不同部分中的类型之间的关系。例如,您可以指定函数传递某种类型,然后返回相同类型的数组

function wrapInArray<T> (input: T): T[] {
   return [T];
}
// To be used like:

const result1 = wrapInArray(1234); // result1 is a number array;
const result2 = wrapInArray('hello'); // result2 is a string array;

在上面的示例中,T 是一个占位符,用于表示传入的任何类型。它的目的是告诉 typescript 事物如何相互关联。你可能事先不知道T是什么,但你仍然可以说输入和输出是相互关联的。


在许多情况下,您希望泛型更加具体。这是因为如果你不具体,那么你就不能在函数内部做太多事情,因为你不知道你正在使用什么类型。通过使用extends ,您可以指定该类型必须具有某些属性。这将禁止任何人使用不具有这些属性的任何内容调用您的函数,然后允许您在函数内随意使用这些属性。例如:

function getLength<T extend { length: number }>(input: T): number {
  // I can access input.length because even though i don't know what input's type is,
  //   i do know that it's illegal to call this function with anything that doesn't
  //   have a length property.
  return input.length;
}

// to be used like:

const len1 = getLength([1, 2, 3]);
const len2 = getLength({ length: 5 });

你的函数只做一件事:返回 Promise<bar> 。您需要指定的类型之间没有关联,并且调用函数时没有可能导致它返回 Promise<bar> 以外的内容。 。所以正确的类型是:

const someBar = new bar();
function foobar(): Promise<bar> {
  return new Promise(resolve => resolve(someBar));
}

更新:

function foobar<T extends Foo>(): T {
  return someBar;
}
const mybar: Bar = foobar<Bar>();

同样,此代码不是通用函数的示例。它总是返回一个栏,而不返回任何其他内容。应该这样输入:

function foobar(): Bar {
  return someBar;
}


const myBar = foobar(); 
// You could add the type explicitly if you prefer, but it's not necessary:
// const myBar: Bar = foobar();
// And since anything that's a Bar necessarily has all the properties of a Foo, you can also do:
const myFoo: Foo = foobar();

关于typescript - 了解 TypeScript 中的通用约束扩展,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57343588/

相关文章:

android - 当我尝试在 Android 11 中读取文件时出现电容器文件系统错误

java - 如何为泛型对实现 equals?

c# - 泛型 C# 的重载运算符

typescript 为嵌套可选对象类型创建默认值

reactjs - 从 componentDidMount() 调用 Typescript Apollo 查询

typescript - 如何在 TypeScript 中覆盖函数类型的参数?

reactjs - 如何轻松获取 ts 类型的 react-native element prop?

Java - 当方法名称不同时将代码提取到泛型方法

java - 用于泛型类型的 Jackson 反序列化器

c# - 如何避免值类型的装箱