Дженерики ReadT/WriteT в Angular Input Signals
В версии 17.1.0 появились типы ReadT
и WriteT
. Рассмотрим их подробнее.
@Component({ }) export class UserProfileComponent { skills = input<ReadT, WriteT>() }
Для чего предназначен ReadT
?
@Component({ }) export class UserProfileComponent { // `ReadT` inferred as `string` from the initial value id = input(''); // Explicitly setting `ReadT` as (string | number) foo = input<string | number>(1) constructor() { effect(() => { // `this.id()` type is string console.log(this.id()); // `this.foo()` type is (string | number) console.log(this.foo()); }); } }
В ситуациях, когда начальное значение не установлено, и явный тип не передан, тип по умолчанию устанавливается как unknown. А если определен тип без значения по умолчанию, автоматически включается тип undefined:
@Component({ }) export class UserProfileComponent { // `ReadT` inferred as `unknown` because we didn't provide initial value id = input(); // Explicilty sets ReadT as (string | number) with no initial value foo = input<string | number>(); // `ReadT` inferred as `unknown` bar = input.required(); // `ReadT` inferred as `string` baz = input.required<string>(); constructor() { effect(() => { // `this.id()` type is `unknown` console.log(this.id()); // `this.foo()` type is (string | number | undefined) console.log(this.foo()); // `this.bar()` type is `unknown` console.log(this.bar()); // `this.baz()` type is string console.log(this.baz()); }); } }
WriteT
применяется преимущественно при работе с transform
. Он определяет типы значений, которые могут быть записаны в Input Soignal
. Функция transform
получает тип WriteT
и должна возвращать значение типа ReadT
.
@Component({ }) export class UserProfileComponent { skills = input<string[], string | string[]>([], { // `value` can be either `string` or `string[]` transform(value) { // Should return `string[]` return Array.isArray(value) ? value : [value]; } }); }
Здесь наш тип сигнала - string[]
, но мы можем передать ввод как string
, так и string[]
. Тип значения переданного в transform
- string | string[],
и она возвращает тип ReadT
, который в данном случае также является string[]
.
Если установить только ReadT
, не определив WriteT
, можно столкнуться с проблемами:
@Component({ }) export class UserProfileComponent { skills = input<string[]>([], { // Results in a compilation error transform(value) { return Array.isArray(value) ? value : [value]; } }); }
В этом случае попытка использовать transform
приведет к ошибке компиляции, потому что WriteT
не определен.
Кроме того, когда явные типы не передаются, WriteT
по умолчанию устанавливается как unknown
:
@Component({ }) export class UserProfileComponent { // `ReadT` = `number`, `WriteT` = `unknown` foo = input(1, { // `value` is `unknown` transform(value) { // Must return a number return 2; }, }); }
В случаях, когда используется required
без передачи каких-либо обобщений, ReadT
будет получен из возвращаемого типа функции transform
, а WriteT
будет undefined
:
@Component({ }) export class UserProfileComponent { // `ReadT` = `number`, `WriteT` = `unknown` foo = input.required({ // `value` is `unknown` transform(value) { return 1; }, }); }
Следует всегда указывать типа при использовании transform
. Это поможет избежать ошибок связанных с типами.
Это перевод оригинального материала