我希望能够指定一个函数的输入对象应该只包含现有接口中存在的键(它不需要具有所有键)。
interface Group {
name: string
}
interface Person {
id: number
name: string
email: string
age: number
}
interface AddedProperties {
groups: Group[]
}
function createPerson<D extends object>( // <-- Should convey, D is an object with some keys of Person
personData: D
): D & AddedProperties {
return Object.assign({}, personData, { groups: [] })
}
interface NameAndAge {
name: string
age: number
}
// Valid: Should be valid
const person: NameAndAge = createPerson({ name: "bob", age: 5 })
// Valid: Should be invalid as 'personality' doesn't exist on Person
const person2 = createPerson({ name: "bob", age: 5, personality: "cheerful" })
这可能是打字稿吗?
答案 0 :(得分:3)
好的,经过一些研究,我现在找到了更好的答案:-)不过,我也将保留其他答案。您可以执行以下操作:
function createPerson<D extends keyof Person>(
personData: Pick<Person, D>
): Pick<Person, D> & AdditionalProperties {
return Object.assign({}, personData, {groups: []});
}
这允许personData
只是Person
的严格子集,并且返回类型将是完全相同的结构加上AdditionalProperties
:
createPerson({name: "Bob", age: 5}); // OK
createPerson({name: "Bob", gender: "male"}); // Type error
createPerson({name: "Bob"}).name; // OK
createPerson({name: "Bob"}).age; // Type error
它如何工作?通用D extends keyof Person
将再次允许添加新字段,我们希望避免这样做。我们不能在泛型类型参数的定义中处理此问题(因为那里只有extends
),而是将实际函数参数限制为
personData: Pick<Person, D>
这将输入限制为仅显示在Person
中的D
的那些属性。我们使用与返回类型相同的类型(与AdditionalProperties
相交)。
您可以在操作here中看到它:
答案 1 :(得分:0)
一种简单的方法是使用Partial<>
:
function createPerson(
personData: Partial<Person>
): Partial<Person> & AddedProperties {
return { ...personData, groups: [] };
}
Partial
接受一个类型并将其所有成员设为可选,从而使您可以指定该类型的属性的任何子集。
此类型的缺点是返回的类型不知道您输入的内容:
createPerson({name: "Bob", age: 5}); // OK
createPerson({name: "Bob", gender: "male"}); // Type error
createPerson({name: "Bob"}).name; // OK
createPerson({name: "Bob"}).age; // OK :-(
如果您也想避免这种情况,请查看我的其他答案。