I want to be able to specify that an input object to a function should only contains keys that are present in an existing interface (it does not need to have all the keys).
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" })
Is this possible in typescript?
You must tell TypeScript if a property is optional. First, if you don't tell TypeScript that a property is optional, it will expect it to be set. Adding ? to the property name on a type, interface, or class definition will mark that property as optional.
TypeScript Interface Define Objects Only In TypeScript, type aliases can define composite types such as objects and unions as well as primitive types such as numbers and strings; interface, however, can only define objects. Interface is useful in typing objects written for object-oriented programs.
The {[key: string]: string} syntax is an index signature in TypeScript and is used when we don't know all the names of a type's properties ahead of time, but know the shape of the values. The index signature in the examples means that when an the object is indexed with a string , it will return a string .
A simple approach is using Partial<>
:
function createPerson(
personData: Partial<Person>
): Partial<Person> & AddedProperties {
return { ...personData, groups: [] };
}
Partial
takes a type and makes all of its members optional, thus allowing you to specify any subset of properties of that type.
The downside of this typing is that the returned type has no knowledge of what you put into it:
createPerson({name: "Bob", age: 5}); // OK
createPerson({name: "Bob", gender: "male"}); // Type error
createPerson({name: "Bob"}).name; // OK
createPerson({name: "Bob"}).age; // OK :-(
If you want to avoid this as well, check out my other answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With