I have a type with some different config objects, like this:
type Types =
| { kind: 'typeA', arg1: string }
| { kind: 'typeB', arg1: string, arg2: string }
I also have type which pulls out just the kind
subtype from the union above:
type InnerType = Types['kind'];
Here innerType
is a union of 'typeA'|'typeb'
as expected.
Lastly I have conditional type which extracts only the non-kind subtypes also from the Types
union:
type ExtractOtherParams<K, T> = K extends { kind: T }
? Omit<K, 'kind'>
: never
So far, this works as expected – if I create a new type called Test
and use the conditional type passing in typeA
then the type is an object containing only arg
type Test = ExtractOtherParams<Types, 'typeA'> // test = { arg1: string }
And if I pass typeb
to the conditional, then it gives object type with arg1
and arg2
properties, e.g:
type Test = ExtractOtherParams<Types, 'typeB'> // test = { arg1: string, arg2: string }
So far, so good. But now when I try to define function which uses this conditional then it does not work as expected. For example:
function test<T extends InnerType>(
kind: T,
others: ExtractOtherParams<Types, T>,
): void {
switch (kind) {
case 'typeA':
console.log(others.arg1);
break;
case 'typeB':
console.log(others.arg1, others.arg2);
}
Here it is mostly correct – I can only switch on the values 'typeA'
or 'typeB'
, any other value not in the original Types union gives error – this is good. But inside second case, it is giving error when I try to access others.arg2
(it says arg2 does not exist on type ‘ExtractOtherParams<{ kind: “typeA”; arg1: string; }, T>’)
But, when I use this function, it works as expected from a consumer POV, for example, if I call the function with typeA
then it will only let me pass object with arg1:
test('typeA', { arg1: 'test' }); // correct, no errors
test('typeA', { arg1: 'test', arg2: 'oops' }); // correct, has error on arg2
test('typeB', { arg1: 'test', arg2: 'works' }); // correct, no errors
test('typeB', { arg1: 'test' }); // correct, has error for missing arg2
What am I missing from the definition of test
function to allow it to access the arg2 inside the second case expression?
I tried function definition without extending, just using generic type, e.g:
test<T>
But this did not make a difference. Unsure what else to try tbh
ts-disciple is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.