Дженерики 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. Это поможет избежать ошибок связанных с типами.
Это перевод оригинального материала