While I working with some TypeScript, I ran into a little dilemma. I wanted to generate random model objects for testing while enforcing only the correct interface properties. I did some Googling, like you may be now, and found a GitHub gist with an interesting tid bit.
type Optional<T> = { [P in keyof T]?: T[P] }
This little nugget was exactly what I was looking for! This type allows you to turn any interface into having all optional fields. So I did a small refactor. Note the use of any
before and after.
export const randomPet = (pet?: any): IPet => ({
id: chance.guid(),
name: chance.name(),
species: chance.word(),
age: chance.age().toString(),
...pet,
});
const expectedPet = randomPet({foo: "bar"}); //legal and wrong
export const randomPet = (optionalPet?: Optional<IPet>): IPet => ({
id: chance.guid(),
name: chance.name(),
species: chance.word(),
age: chance.age().toString(),
...optionalPet,
});
const expectedPet = randomPet({foo: "bar"}); //TS Error
const expectedPet = randomPet({name: "Kevin"}); //legal and correct
Now when I want to generate a random IPet
, TypeScript will remind me that I can only use fields that exist on the IPet
interface, yet, allow me to pass any override value that matches the interface.