TypeScript: Using a condition mapped type on a type that extends another type causes error

TypeScript Version: 2.8.1

Search Terms: conditional types, extends

Code

// A *self-contained* demonstration of the problem follows...
interface StringOption{
    type: "string";
}

interface NumberOption{
    type: "number";
}

type ValidTypes = {
    [key: string]: string | number;
}

interface ISampleObject extends ValidTypes {
    stringParam: string,
    numberParam: number
}

type MappedOptions<T extends ValidTypes> = {
    readonly [P in keyof T]: T[P] extends string ? StringOption : 
        T[P] extends number ? NumberOption : never;
}

const mappedObject: MappedOptions<ISampleObject> = {
    stringParam: {type: "string"},
    numberParam: {type: "number"}
}

Expected behavior: This should compile correctly

Actual behavior: A compilation error is shown:

Property 'stringParam' is incompatible with index signature.
Type '{ type: "string"; }' is not assignable to type 'never'.

Playground Link: Playground Link

This code sample works fine if the ValidTypes type is removed. I am using this type to limit the property types that can be used with this mapped type. Without it any type could be used and complex types containing functions and booleans could be created.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 16 (5 by maintainers)

Most upvoted comments

@kpdonn many thanks for that last suggestion. I hadn’t even realised that was a problem. I am surprised that this

type SampleOrConfiguredOption<T> = SampleValueCommandOption<T> | OptionWithTypeAndMultiple<T>;

produces a type that can mix properties from SampleValueCommandOption and OptionWithTypeAndMultiple.

I see that your suggestion

type SampleOrConfiguredOption<T> = 
    ( SampleValueCommandOption<T> & Partial<OptionWithTypeAndMultiple<T>> )
    | 
    (OptionWithTypeAndMultiple<T> & Partial<SampleValueCommandOption<T>>);

specifically allows that mixing but then enforces the correct type and multipleValues values.

Thanks again. That’s another potential bug squashed.

Thanks, I’ll just try and bend my head round that last post and see if I can apply it to my code 😃