1

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];


6
  • When I follow the link to the playground, I get only one line of code. Could you please fix this? Commented Mar 8, 2022 at 14:51
  • @www.admiraalit.nl sorry seems to work now Commented Mar 8, 2022 at 14:55
  • I still have the same problem. Commented Mar 8, 2022 at 15:12
  • I don't, just copy paste what is in the code box then Commented Mar 8, 2022 at 15:33
  • Playground Commented Mar 8, 2022 at 16:31

1 Answer 1

1

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' }
Sign up to request clarification or add additional context in comments.

1 Comment

That doesn't work if 'optionalY' needs to be inferred by typescript, e.g. when you are passing {type: "optionalY"} as an object into a function as an argument. If you try to apply this to the example I gave it unfortunately looses type information and just unions everything together :(

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.