Twiggeh
Twiggeh

Reputation: 1160

Typescript Conditional Type not working when used in a function argument

I want a key of an interface to be added conditionally, for that use-case I tried doing

key: a extends b ? keyValue : never

but not only does that break when a is generic, it also requires me to pass never as the value to the key ?

The questions are, how do I make that genric work and how to "filter" out never types so that I don't have to pass them explicitly.

Typescript Playground with the below example

export type Component<T extends ComponentList> = {
    id: T;
    kids: GetProps<T> extends { children: Record<string, any> } ? string[] : never;
};


// Change Wrapper to Button and you will see that kidType changes between string[] and never like it is supposed to
// But as an argument to reComponent it always thinks that the kids option is never, and it also asks me to give it a never option ??
type WrapperProps = GetProps<"Wrapper">
type kidType = WrapperProps extends {children: Record<string, any> } ? string[] : never;   

const reComponent = <T extends ComponentList>(arg0: Record<string, Component<T>>) => {};

reComponent({
    button1: {id: "Button" },
    wrapper1: {id: "Wrapper", kids: [""]},
});


var Wrapper = ({
    children,
}: {
    children: Component<'Wrapper'> | Component<'Button'>
}) => {
    return "react.component"
};

var Button = ({
    text,
}: {
    text: string
}) => {
    return 123
};

var Components = {
    Wrapper,
    Button,
};


export type ComponentList =
    | 'Wrapper'
    | 'Button'

export type GetProps<T extends ComponentList> = Parameters<typeof Components[T]>[0];


Upvotes: 1

Views: 122

Answers (1)

www.admiraalit.nl
www.admiraalit.nl

Reputation: 6089

Type never cannot be used to remove a key from an interface. For example:

type testNever = {
    x : string;
    y : never;
}

var tn: testNever = { x: 'ab' }   // error: property 'y' is missing

Type never is meant to be used as the type of a function to indicate that it will never return. See TypeScript Handbook, section 'More on functions'

You can use the question mark to make a key optional and use keyword Required to make a version of the type in which the key is required. Here is an example:

type TypeWithOptionalY = {
    x : string;
    y? : string;
}

type TypeWithRequiredY = Required<TypeWithOptionalY>

type WithOrWithoutY = 'requiredY' | 'optionalY'

type ConditionalY<T extends WithOrWithoutY> =
    T extends 'requiredY'
        ? TypeWithRequiredY
        : TypeWithOptionalY

var objWithoutY : ConditionalY<'optionalY'> = { x: 'abc' }   
var objWithY : ConditionalY<'requiredY'> = { x: 'abc', y: 'def' }

Upvotes: 1

Related Questions