我有类Person的对象和MoneyHolder接口。如何创建一个新对象Holder,克隆Moneyholder中定义的字段子集?
class Person {
constructor(public id: number,
public name: string,
public money: number) { }
}
interface MoneyHolder {
id: number;
money: number;
}
let person = new Person(1, 'Jack', 100);
let holder = ...????????
PS:我寻求自动解决方案而无需手动枚举接口字段。
答案 0 :(得分:1)
接口在编译期间被删除,因此它们不会在运行时存在,但Person
类与MoneyHolder
合同完全兼容:
class Person {
constructor(public id: number,
public name: string,
public money: number) { }
}
interface MoneyHolder {
id: number;
money: number;
}
let person = new Person(1, 'Jack', 100);
let moneyHolder: MoneyHolder = person;
所以你可以简单地将person
传递给需要MoneyHolder
的地方,一切都很好,这要归功于结构打字。
如果要表示API合约和地图字段,可以使用类:
class Person {
constructor(public id: number,
public name: string,
public money: number) { }
}
interface MoneyHolder {
id: number;
money: number;
}
class MoneyHolder {
public id: number;
public money: number;
constructor(moneyHolder: MoneyHolder) {
this.id = moneyHolder.id;
this.money = moneyHolder.money;
}
}
let person = new Person(1, 'Jack', 100);
let moneyHolder = new MoneyHolder(person);
或者你可以进入动态土地,但失去所有的类型安全:
class Person {
constructor(public id: number,
public name: string,
public money: number) { }
}
class MoneyHolder {
public id: number = 0;
public money: number = 0;
constructor(moneyHolder: any) {
for (let prop of Object.getOwnPropertyNames(this)) {
this[prop] = moneyHolder[prop];
}
}
}
let person = new Person(1, 'Jack', 100);
let moneyHolder = new MoneyHolder(person);
答案 1 :(得分:1)
当TypeScript编译为JavaScript时,类型信息(包括接口)将被删除。因此,您无法在运行时引用MoneyHolder
,以便枚举您关注的id
和money
键。
可以做的是创建您关心的键数组,TypeScript可以使用该数组的类型推断 MoneyHolder
类型为了你。以下是如何让TypeScript推断字符串文字数组:
function stringLiteralArray<K extends string>(...arr: K[]): K[] {
return arr;
}
const moneyHolderKeys = stringLiteralArray('id', 'money');
辅助函数stringLiteralArray()
为您做推理。
(除了)
如果你刚刚这样做了:
const moneyHolderKeysOops = ['id', 'money']; // string[]
它将被推断为string[]
,它会丢失您关心的关键信息。你可以这样做:
const moneyHolderKeysTedious = ['id', 'money'] as ('id'|'money')[];
但这很乏味且重复。这就是我们创建stringLiteralArray()
辅助函数的原因。
现在您的moneyHolderKeys
数组的推断类型为('id' | 'money')[]
。以下是编写通用克隆函数的方法:
function clonePart<T, K extends keyof T>(keys: K[], obj: T): Pick<T, K> {
const ret = {} as Pick<T, K>;
keys.forEach(k => ret[k] = obj[k]);
return ret;
}
请注意返回值Pick<T,K>
,它是T
的超类型,仅指定K
的键。它是标准TypeScript库的一部分,其定义为:
/**
* From T pick a set of properties K
*/
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
现在你可以使用它了:
let person = new Person(1, 'Jack', 100);
let holder = clonePart(moneyHolderKeys, person);
如果您检查holder
,您会看到它是{id: number, money: number}
类型。嘿,那是MoneyHolder
!我们现在可以根据需要命名:
type MoneyHolder = typeof holder;
这样有效。它与你所要求的有点相反,但是它完成了工作,没有任何重复。你可以see it in action in the TypeScript Playground。希望有所帮助;祝你好运!