Make property non-optional if it was passed in object literal
Consider the following example (Playground link)
interface Foo<T> {
kind: string;
value?: T;
}
function foo<T>(props: Omit<Foo<T>, "kind">) : Foo<T> {
return {kind:"foo", ...props};
}
function testOptUnknown(v?: unknown) {
}
function testNumber(v: number) {
}
const foo1 = foo({});
const foo2 = foo({value: 42});
testOptUnknown(foo1.value);
testNumber(foo2.value); // <--- does not compile
What I am trying to achieve is that the "builder"-function foo
specialises Foo
's value
to be non-optional if a given value for value
was passed.
BTW. Turning value?: T
into value: T
will not work for me because I am using exactOptionalPropertyTypes
.
You can use a type parameter for the actually passed-in input parameter and use that type parameter to construct your return type. That way, the compiler will propagate its knowledge of the type of the actual argument:
interface Foo<T> {
kind: string;
value?: T;
}
function foo<X, T extends Omit<Foo<X>, "kind">>(props: T) : T & {kind: 'foo'} {
return {kind:"foo", ...props};
}
function testOptUnknown(v?: unknown) {
}
function testNumber(v: number) {
}
const x = {
'a': 1
}
const y = {...x, b: '2'}
const foo1 = foo({});
const foo2: Foo<string> = foo({});
const foo3 = foo({value: 42});
testOptUnknown(foo1.value);
testOptUnknown(foo2.value);
testNumber(foo3.value);
Playground link