在Typescript中,<t>意味着什么?

时间:2018-04-03 04:01:44

标签: typescript

export declare function createEntityAdapter<T>(options?: {
    selectId?: IdSelector<T>;
    sortComparer?: false | Comparer<T>;
}): EntityAdapter<T>;

有人可以向我解释一下这意味着什么?我知道<>是类型断言,但我不知道'T'是什么。如果有人能够向我解释这个功能正在做什么,它也会有所帮助。

4 个答案:

答案 0 :(得分:38)

  

有人可以向我解释一下这意味着什么?

这是打字稿Generics声明。

摘录:

  

软件工程的一个主要部分是构建组件,这些组件不仅具有定义明确且一致的API,而且还可以重用。能够处理当今数据以及未来数据的组件将为您提供构建大型软件系统的最灵活功能。

     

在C#和Java等语言中,工具箱中用于创建可重用组件的主要工具之一是泛型,即能够创建可以在各种类型而不是单个类型上工作的组件。这允许用户使用这些组件并使用他们自己的类型。

  

我不知道&#39; T&#39;是

'T'将是在运行时声明的类型,而不是 compile 时间。 T变量可以是任何非声明的变量(我无法找到引用,但我会假设可以用于变量名的任何有效字符集)。类似地,在中,如果T表示的类型不是值类型而是更复杂的类型(类)或接口,则可以将其命名为/ delcared为TVehicle或{{1}帮助表示未来程序员的有效类型(并且可以被认为是最佳实践,因为TAnimal只是不直观)。我更喜欢T,因为我知道大写字母T表示泛型类型。 TSomethingWSometing也有效,但我不喜欢它。 (例如,微软API几乎总是TContextTEntity

  

如果有人能向我解释这个功能在做什么,那也很有帮助。

该功能不是任何事情。这更多地声明了一种可以具有多个运行时类型值的函数。我没有解释,而是直接从上面的链接中摘录。

ASomething

可以像:

一样使用
function identity<T>(arg: T): T {
  return arg;
}

// type of output will be 'string'
let output = identity<string>("myString");  

// type of output will be 'string', the compiler will figure out `T`
// based on the value passed in
let output = identity("myString");  

可能会提出这样的问题:

  

为什么要使用泛型

好的Javascript有数组,但是当你从数组中检索一个值时,它实际上可以是任何东西(typescript:// type of output will be 'number' let output = identity(8675309); )。使用打字稿,您可以通过声明类型来获得类型安全性:

any

现在,数组中的每个值都有一个类型。如果您尝试将字符串放入此数组中,Typescript将抛出编译时错误。当你检索一个值时,你会得到类型安全和智能感知(取决于你的编辑器):

 // Array<T>
 let list: number[] = [1, 2, 3];
 // or 
 let list: Array<number> = [1, 2, 3];

声明类型&#39; d通用约束。 Open - Closed Principle的一个很好的例子。

  

在面向对象的编程中,开放/封闭原则规定&#34;软件实体(类,模块,函数等)应该是可以扩展的,但是关闭以进行修改&#34 ;; [1]即,这样的实体可以在不修改源代码的情况下扩展其行为。

在下面的示例中,任何人都可以扩展Human或Cheeah,甚至可以创建自己的派生类型,Logger功能可以继续工作而无需任何修改。

class Person {
  FirstName: string;
}

let people: Array<Person> = [];
people.push({ FirstName: "John" } as Person);

let john = people.pop();  
// john is of type Person, the typescript compiler knows this
// because we've declared the people variable as an array of Person

console.log(john.FirstName);  

Working Example

在上一个示例中,我使用Generic Constraint来限制interface IAnimal { LegCount: number; } class Cheetah implements IAnimal { LegCount: number = 4; } class Human implements IAnimal { LegCount: number = 2; } public class Logger<TAnimal extends IAnimal> { public Log(animal: TAnimal) { console.log(animal.LegCount); } } var logger = new Logger(); var human = new Human(); logger.Log(human); 类型的程序员可以用来为从TAnimal接口派生的类型创建Logger实例。这允许编译器验证IAnimal类始终假定类型具有属性Logger

答案 1 :(得分:6)

您提供的示例是具有通用参数的函数。 T(不一定是T。您可以将其称为G。)称为通用模板,其中T的实际类型在运行时被替换。< / p>

想象一下EntityAdapter有以下实现:

interface EntityAdapter<T> {
   save(entity: T);
}

下面的代码返回一个EntityAdapter,其内容为anyany可以是数字,字符串,对象或任何东西。

let adapter1 = createEntityAdapter<any>(<parameters here>)

下面的代码返回一个EntityAdapter,其内容为Car

let adapter2 = createEntityAdapter<Car>(<parameters here>)

基本上Carany更具体,因此您可以获得额外的类型安全性。那么这有什么帮助?

简而言之,通用模板可以为您提供额外的类型安全性。例如,

adapter1.save('I am string') // this works because `T` is `any`
adapter1.save(new Car()) // this also works because `T` is `any`

adapter2.save('I am string') // this wont works  because `T` is `Car`, typescript compiler will complains
adapter2.save(new Car()) //this works because `T` is `Car`

希望这有帮助。

答案 2 :(得分:6)

遗憾的是,我没有达到为 @Erik Philips 评分最高的答案下的精彩讨论做出贡献所需的“50 个声望点”,但值得注意的是,截至 2021 年 3 月,Typescript文档已更新以弃用文档中的 <T>,而支持使用 <Type>Link

就我而言,这令人困惑,因为我找不到演示 T 用法的旧文档。但是,Erik Philips 的回答帮助我理解,这以前是在较旧(现已弃用)的 Typescript 文档中展示的约定。

更新当前答案以包含此信息可能会有所帮助。

答案 3 :(得分:0)

它被称为泛型,帮助我们编写安全而灵活的函数。它为类型提供变量。简而言之,您可以创建适用于不同类型的函数、接口或类,而无需预先指定类型。 下面是一些演示代码来解释我们为什么使用它以及如何使用它。

// any is too general ,and it loses the meaning of using typescript

function insertAtBegining(array:any[],value:any) {
    let newArr = [value, ...array];
    return newArr;
}

// if we specify the type number , this function will lost it's utility 

function insertAtBegining(array:number[],value:number) {
    let newArr = [value, ...array];
    return newArr;
}

// if we specify the type string , this function will lost it's utility 

function insertAtBegining(array:string[],value:string) {
    let newArr = [value, ...array];
    return newArr;
}

const demoArr = [1, 2, 3];

const updatedArr = insertAtBegining(demoArr, 4);
// more generic functions

function insertAtBegining<T>(array:T[],value:T) {
    let newArr = [value, ...array];
    return newArr;
}