В 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`
надеюсь, что это помогает.