我想通过在tsconfig.json
中设置"strictTemplates": true
来更新我的应用程序,使其使用Angular的模板Strict模式。在使用新配置运行ng serve
之后,我出现了一个奇怪的错误。
我有一个在很多地方使用的共享组件
@Component({
selector: 'my-shared-component',
...
})
export class SharedComponent {
@Input() selectedId: string | number;
@Output() selectedIdChange = new EventEmitter<string | number>()
@Input() disabled: boolean;
...
}
并且通过<my-shared-component disabled="true">
会抛出一个错误,这是可以的。
当我试图将number
传递到@Input() selectedId: string | number;
时,问题就开始了,即:
export class OtherComponent {
myNumberId: number;
...
}
<my-shared-component [(selectedId)]="myNumberId">
然后抛出一个错误:
TS2322:类型"string|number"不可分配给类型"number">
我不想用string | number
替换myNumberId
的类型,因为它也用于另一个具有@Input id: number
(并且必须是数字(的组件中。另外,myNumberId
来自服务器,我知道这是一个数字,所以我认为如果我用string | number
替换它,会导致设计不好。
我也不想使用strictAttributeTypes配置为false,因为之后<my-shared-component disabled="true">
将不再抛出错误。
我想知道是否存在某种typescript实用程序类型(或类似的类型(,使@Input() selectedId: string | number
只接受字符串或数字,而不强制父级的变量为string | number
。或者我可以做其他事情来解决这个问题吗?
好吧,它正确地抛出了一个错误-输出EventEmitter
将发出string
或number
,这将尝试为严格类型的数字赋值。
您可以尝试在OtherComponent
:中分离setter和getter
_myNumberId: number;
get myNumberId(): number {
return this._myNumberId;
}
get myNumberId(value: string | number): number {
if (typeof value === 'string') {
// This is a stub, you might want to go with something else like parseFloat()
// or just throw.
this._myNumberId = parseInt(value, 10);
} else {
this._myNumberId = value;
}
}
这部分地保持了检查类型的number
,如果值被提取,并且仍然允许从string
或number
设置值,因此它将删除编译错误。但这不是一个好的解决方案,因为它看起来像一种代码气味;松开";setter上的类型检查。
如果你退后一步,从更大的角度来看——也许你应该定义什么是";Id";在您的应用程序中,并在通用组件中使用该类型?正在进行的事情:
export type MyId = string | number;
然后,您的组件可以使用泛型扩展该类型,这将进行严格的类型检查:
@Component({
selector: 'my-shared-component',
...
})
export class SharedComponent<T extends MyId> {
@Input() selectedId: T;
@Output() selectedIdChange = new EventEmitter<T>()
@Input() disabled: boolean;
...
}
这将允许在双向绑定中将string
或number
指定为输入/输出,并在两个位置将类型强制为其中的一个。稍后,如果您决定需要将额外的逻辑应用于Id
本身,则可以在一个位置更改它(类型定义(,并查看它是否违反了任何类型检查。
当然,你总是可以不定义类型,并这样做:
export class SharedComponent<T extends string | number> {
但是,您可能还想在几个不同的地方强制执行这一点,因此自定义值类型似乎是一个不错的方法。
这里有一个使用泛型方法的stackblitz,它在双向绑定中正确地分配了string
和number
值,但未能分配不同的类型(Date
(。如果删除日期分配,它将正确编译。
您可以尝试用string & number
替换string | number
。
你也可以试着这样发送:
<my-shared-component [(selectedId)]="+myNumberId">