Reputation: 12818
This code:
interface Dog {
name?: string;
size?: number;
}
const entity: Dog = {
name: 'max',
}
const name: string = entity.name;
Causes this error:
Type 'string | undefined' is not assignable to type 'string'.
I can avoid the error by removing the entity
type:
interface Dog {
name?: string;
size?: number;
}
const entity = {
name: 'max',
}
const name: string = entity.name;
But then I lose the auto-complete feature.
Is there a way to win both? To have autocomplete, and let the code know which keys are there based on the initializer?
E.g. using Required<Dog>
isn't a good solution because I don't want to initialize size
. The real use-case I have actually has a much bigger interface.
Upvotes: 1
Views: 332
Reputation: 19441
in typescript 4.9 we can use the satisfies operator:
interface Dog {
name?: string;
size?: number;
}
const myDog = {
name: 'bello',
} satisfies Dog;
const dogName: string = myDog.name;
What I do is to define a generic identity check function that can be used for any interfaces:
function identityCheck<T = never>() {
return <I>(input: I & T) => input as I;
}
then create a concrete check-function for the Dog
interface:
const dogIdentity = identityCheck<Dog>();
finally use it to create the constant:
const myDog = dogIdentity({
name: 'bello',
})
// name is of type string
myDog.name.slice();
Upvotes: 2
Reputation: 33111
You can infer it with help of extra function:
interface Dog {
name?: string;
size?: number;
}
type IsValidDog<Animal> = Required<Dog> extends Animal ? Animal : never;
const builder = <Animal extends Dog>(animal: IsValidDog<Animal>) => animal
/**
* Ok
*/
const result = builder({
name: 'max',
})
result.name // ok
result.size // expected error
const result2 = builder({
name: 'max',
size: 42
})
result2.name // ok
result2.size // ok
/**
* Error
*/
const result3 = builder({ name: 'Sharky', unknown: 2 }) // expected error
const result4 = builder({ nAme: 'Sharky', size: 2 }) // expected error
const result5 = builder({ name: 'Sharky', size: 2, surname: 'Doe' }) // expected error
builder
function expects/allows exact a Dog
object. It allows use less properties, because all of them are optional but it disaalow any extra properties to bu used, see result5
.
IsValidDog
- checks whether Dog
with all required props extends passed object interface. If you pass an object with some extra properties, this check will fail.
You can find more validation techniques in my blog
Upvotes: 1