0

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.

Is there a way to solve this problem using conditional types?

3
  • Possible duplicate of Typescript custom restriction with Generics Commented Oct 24, 2019 at 0:55
  • The issue is the same as in the linked question: unresolved conditional types are essentially opaque and the compiler doesn't see anything as assignable to them. There is a suggestion that, if implemented, would maybe solve the problem, but until then you either need to use type assertions (or the equivalent, like overload signatures) or refactor away from conditional types. Commented Oct 24, 2019 at 0:58
  • Here's a non-conditional ReverseId which happens to work but I wouldn't use it in any prod environment: type ReverseId<T extends ValidObjectId> = ({ [k: string]: number } & { [k: number]: string })[T["id"]]; Commented Oct 24, 2019 at 1:05

0

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.