如何在TypeScript中获取setter属性类型并解决封装参数匹配问题
获取TypeScript对象类型中Setter的属性类型
先看这个场景:定义一个getter和setter类型不同的对象类型:
type Foo = { get bar(): number; set bar(value: number | string); }
当用索引访问获取属性类型时,只能拿到getter的类型:
type Bar = Foo["bar"]; // 类型为number
现在需要获取setter的类型(也就是示例里的number | string),试了下面的泛型但没效果:
type SetterType<T, U extends string> = T extends { set [key in U]: infer P } ? P : never; type Bar = SetterType<Foo, "bar">;
应用场景
现有这样的API:
const foo = addFoo(); // addFoo函数返回Foo类型 foo.bar = 123; foo.bar = "123"; // setter能正常接收string类型 foo.baz = true; // 其他属性...
想封装这个函数,通过传入字面量对象设置属性,内部用Object.assign实现:
function myAddFoo(properties: Partial<Foo>): Foo { const foo = addFoo(); Object.assign(foo, properties); return foo; } const foo = myAddFoo({ bar: "123", // 报错:`bar`必须是number | undefined baz: true, // 其他属性... });
这里的问题是字面量里的bar没法用setter支持的number | string类型,所以得让函数参数兼容setter类型,也就是要推断出所有setter的类型(比如{ bar: number | string }),再调整参数类型:
type FooSetters = /* 推断所有setter类型,如`{ bar: number | string }` */; function myAddFoo(properties: Partial<Omit<Foo, keyof FooSetters> & FooSetters>): Foo
解决方案
1. 提取单个属性的Setter类型
修改泛型,直接匹配属性的setter签名:
type SetterType<T, K extends keyof T> = T[K] extends { set: (value: infer P) => void } ? P : never; // 测试 type BarSetter = SetterType<Foo, "bar">; // number | string
2. 提取对象所有属性的Setter类型
如果要一次性提取所有带setter的属性类型,可以用映射类型:
type ExtractSetters<T> = { [K in keyof T as T[K] extends { set: any } ? K : never]: T[K] extends { set: (value: infer P) => void } ? P : never }; // 测试 type FooSetters = ExtractSetters<Foo>; // { bar: number | string }
3. 修正封装函数的参数类型
用上面的ExtractSetters调整myAddFoo的参数类型,让它同时兼容getter和setter的类型:
type ExtractSetters<T> = { [K in keyof T as T[K] extends { set: any } ? K : never]: T[K] extends { set: (value: infer P) => void } ? P : never }; type FooSetters = ExtractSetters<Foo>; function myAddFoo(properties: Partial<Omit<Foo, keyof FooSetters> & FooSetters>): Foo { const foo = addFoo(); Object.assign(foo, properties); return foo; } // 现在可以正常传入string类型的bar了 const foo = myAddFoo({ bar: "123", // 不再报错 baz: true, });
原理说明
在TypeScript类型系统中,带getter和setter的属性会被识别为包含get和set方法的对象类型。通过条件类型的infer关键字,可以从setter的函数签名里提取出参数类型,也就是setter接受的值类型。
内容的提问来源于stack exchange,提问作者Cmo Sekil
相关产品推荐
相关产品推荐

