В Typescript что означает?

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

может кто-нибудь объяснить мне, что это значит? Я знаю <> утверждение типа, но я не знаю, что 'T' есть. Было бы также полезно, если бы кто-нибудь мог объяснить мне, что делает эта функция.

2 ответов


может кто-нибудь объяснить мне, что это значит?

это машинописные тексты дженериков декларации.

выдержка:

основной частью разработки программного обеспечения является создание компонентов, которые не только имеют четко определенные и последовательные API, но также многоразовые. Компоненты, способные работать как с данными сегодняшнего дня, так и с данными завтрашнего дня, дадут вам наиболее гибкие возможности для создание больших программных систем.

в таких языках, как C# и Java, одним из основных инструментов в toolbox для создания повторно используемых компонентов является generics, то есть возможность создания компонента, который может работать над различными типами, а не над одним. Это позволяет пользователям использовать эти компоненты и использовать свои собственные типы.

.

я не знаю, что такое "Т".

'T' будет тип объявлено во время выполнения вместо compile времени. The T переменная может быть любой необъявленной переменной (я не мог найти ссылку, но я бы предположил любой допустимый набор символов, которые могут быть использованы для имен переменных). Аналогично в c#, если тип T represents - это не тип значения, а более сложный тип (класс) или интерфейс, его можно назвать/delcared как TVehicle или TAnimal чтобы помочь обозначить допустимый тип для будущих программистов (и может быть считается лучшей практикой, потому что просто T не понятный). Я предпочитаю TSomething потому что я знаю, что верхний регистр T означает общий тип. WSometing или ASomething также действителен, но я просто не предпочитаю его. (Microsofts APIs почти всегда TContext или TEntity например).

было бы также полезно, если бы кто-нибудь мог объяснить мне, что делает эта функция.

функция не делаешь ничего. Это более объявить тип функции, которая может иметь несколько значений типа. Вместо того, чтобы объяснять это, я включу выдержку, взятую непосредственно из ссылки выше.

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");  

или

// type of output will be 'number'
let output = identity(8675309);  

что может вызвать вопрос:

зачем использовать дженерики

Ну Javascript имеет массивы, но когда вы извлекаете значение из массива, оно буквально может быть чем угодно (typescript:any). С typescript вы получаете безопасность типа, объявив их как:

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

теперь каждое значение в массиве имеет тип. Typescript выдаст ошибку времени компиляции, если вы попытаетесь поместить строку в этот массив. И вы получаете type-safety и intellisense (в зависимости от вашего редактора) при получении значения:

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);  

объявление типовых ограничений. Очень хороший пример Открыть-Закрыть Принципал.

в объектно-ориентированном программировании принцип open/closed гласит: "программные объекты (классы, модули, функции и т. д.) должен быть открыт для расширения, но закрыт для изменения"; [1] то есть такой объект может позволить расширить свое поведение без изменения своего исходного кода.

в следующем примере любой может расширить Human или Cheah или даже создать свой собственный производный тип и функции регистратор будет продолжать работать без каких-либо изменений.

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 класс всегда предполагает, что тип имеет свойство LegCount.


приведенным примером является функция с общим параметром. T (который не должен быть T. Вы могли бы назвать это G.) называется общим шаблоном, где фактический тип T заменен во время выполнения.

представьте, что EntityAdapter имеет следующую реализацию:

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

ниже код возвращает EntityAdapter, содержимое которого any. any может быть число,строка, объект или что-нибудь.

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

ниже код возвращает EntityAdapter, содержимое которого Car.

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

в принципе Car более конкретную, чем any так, что вы сможете получить дополнительную безопасность типа. И как это поможет?

в двух словах, универсальный шаблон может дать вам дополнительную безопасность типа. Например,

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`

надеюсь, что это помогает.