Skip to content

Problem with generics and conditional types #34687

Closed
@lffg

Description

@lffg

TypeScript Version: 3.7-beta

Search Terms: conditional types generic problem


Note: I'll say "reverse type" a lot in this issue. In such context, the reversed type of a number is string, and the reversed type of a string is a number.

I have the following code:

type Id = string | number;

type ObjectId<T extends Id> = {
  id: T;
};

type ValidObjectId = ObjectId<string> | ObjectId<number>

type ReverseId<T extends ValidObjectId> = T['id'] extends number ? string : number;

function encodeObjectId<T extends ObjectId<number>>(
  obj: T
): ReverseId<T> {
  const id = obj.id;

  // Why does the following does not accept a string type?
  // As it's the reverse of type number, because of the `ReverseId` type, it should be working.
  return id.toString();
}

Playground link.

In it, I have the type ReverseId, which converts the type of the id property. For example, if the given object id property has a number type, it will return string; and if the given object's id property has a string type, the number type will be returned.

And that actually works:

type Id = string | number;

type ObjectId<T extends Id> = {
  id: T;
};

type ValidObjectId = ObjectId<string> | ObjectId<number>

type ReverseId<T extends ValidObjectId> = T['id'] extends number ? string : number;

// The `t` constant has a `number` type, which is the "reverse" of the `string`
// type, used in the given `ObjectId`.
const t: ReverseId<ObjectId<string>> = 1;

Playground link.

The problem is: when the ObjectId comes from a generic, as we saw in the encodeObjectId function in the first example, the type does not work.

I think that this is a problem, because it work when the ObjectId type does not come from a generic, and don't work when this type comes from a generic.

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions