想要的效果是tag参数输入svg就对应svg的参数, 输入circle就对应circle的参数;
但是if(tag === 'circle')
语句中就是不能正常识别, 很纳闷, 也不知道怎么解决. 求教
interface NsTag {
svg: {
/** 宽度 */
width: string;
};
circle: {
/** 圆的中心点到屏幕左边的距离 */
cx: string;
/** 圆的中心点到屏幕上边的距离 */
cy: string;
/** 半径 */
r: string;
};
}
createNsTag('svg', {
width: '1',
});
function createNsTag<Tag extends keyof NsTag>(tag: Tag, obj: NsTag[Tag]) {
if(tag === 'circle') {
/**
* 此处"cx"抛错错误如下
* 类型“{ width: string; } | { cx: string; cy: string; r: string; }”上不存在属性“cx”。
* 类型“{ width: string; }”上不存在属性“cx”。ts(2339)
*/
obj.cx = '1';
}
const eleNs = document.createElementNS('http://www.w3.org/2000/svg', tag);
for (const attr in obj) {
if (Object.prototype.hasOwnProperty.call(obj, attr)) {
/**
* 此处"element"抛错如下
* 不能将类型“NsTag[Tag][Extract<keyof NsTag[Tag], string>]”分配给类型“string”。
* 不能将类型“NsTag[Tag][string]”分配给类型“string”。ts(2322)
*/
const element: string = obj[attr];
eleNs.setAttribute(attr, element)
}
}
}
两个办法,一是使用类型断言函数(下面代码中对 circle 的处理),另一种是使用类型转换(对 svg 的处理)
道理:虽然在使用的时候可以知道
obj
的具体类型,但是在定义的时候并不知道啊。虽然 if 里判断了 tag,但是 TSC 不会去对 obj 进行相关类型推断,过程太复杂了,尤其是对普适性需求的时候,所以自己加类型断言。不过自己一个个去写写类型断言真的很累,不如直接做类型转换。还有一个通用点的
is
函数写法,把 key 传进去如果你要问我为什么
is
就可以推断……我只能告诉你,它不是推断的,是强制的。如果把它的返回类型改成obj is NsTag["circle"]
,你会发现is("svg" ...)
推断出来obj
仍然是NsTag["circle"]
类型。