网站搜索

基于属性值的 TypeScript 泛型


我想要有一个接口,其中的泛型类型基于该接口中某个属性的值:

interface Book<T extends BookType> {
  type: T,
  location: Shelf<T>,
}

而不是使用以下方式来定义泛型类型:

const book: Book<BookType.Technology>;

我想

const book: Book<???>;
book.type = BookType.Technology;

之后,location 被“提示”具有类型 Shelf<BookType.Technology>

在 TypeScript 中这是可能的吗?

答案#1

TypeScript 并不真正支持像你想要的那样先创建空对象然后再赋值属性。通常这里的解决方法是使用类型断言来强类型化空对象……但是你不想自己写出完整类型 Book<BookType.Technology>,所以这不是一个好建议。你希望 BookType.Technology 部分能进行类型推断,但那行不通,因为编译器直到下一行才知道 type 会是 BookType.Technology。而且类型缩小不能向回工作。

在 TypeScript 中的最佳实践是在单个语句中创建一个强类型对象,而不是在多个语句中逐个添加属性。这对编译器来说更容易理解。如果可以的话,我建议使用一个辅助函数,它会为你推断 Book<T> 中的 T。像这样:

const asBook = <T extends BookType>(book: Book<T>) => book;

当你使用它时:

asBook({
  type: BookType.Technology,
  location: ... // this is hinted as Shelf<BookType.Technology> 
})

如你所愿,location 的类型将为你提示为 Shelf<BookType.Technology>。

希望这能帮到你;祝你好运!

代码链接