Conditional tests comparing indexed types using different branded strings doesn't seem to differentiate as I expect.
type Brand<K, T> = K & { __type: T };
type CatID = Brand<string,'cat'>;
type BirdID = Brand<string,'bird'>;
const x1: {[id:CatID]:string} extends {[id:BirdID]:boolean} ? true : false;
// ^? const x1: true
const x2: {[id in CatID]:string} extends {[id in BirdID]:boolean} ? true : false;
// ^? const x2: true
const x3: Record<CatID,string> extends Record<BirdID,boolean> ? true : false;
// ^? const x3: true
const x4: CatID extends BirdID ? true : false;
// ^? const x4: false
The indexes are different types (branded differently, at least), and even the values are different types (string vs. boolean). Why would those first three extends
conditionals return true? As a final test, I checked if the branded types "extend" each other, and typescript reports that they do not.
Any insight here appreciated. I'd like to be able to differentiate types by their index signature.
CodePudding user response:
I can't speak to the deep "why" you're looking for, but re:
I'd like to be able to differentiate types by their index signature
...you can tell those types apart using keyof TheObjectType extends CatID
:
type Brand<K, T> = K & { __type: T };
type CatID = Brand<string, "cat">;
type BirdID = Brand<string, "bird">;
type Cats = {
[id: CatID]: string;
};
type Birds = {
[id: BirdID]: string;
};
type CatCheckAgainstCatID = keyof Cats extends CatID ? true : false;
// ^? type CatCheckAgainstCatID = true
type CatCheckAgainstBirdId = keyof Cats extends BirdID ? true : false;
// ^? type CatCheckAgainstBirdId = false
type BirdCheckAgainstCatID = keyof Birds extends CatID ? true : false;
// ^? type BirdCheckAgainstCatID = false
type BirdCheckAgainstBirdID = keyof Birds extends BirdID ? true : false;
// ^? type BirdCheckAgainstBirdID = true
Beware, though, that a union can confuse the issue (as is often the case):
type Chimera = Birds | Cats;
type X = keyof Chimera extends CatID ? true : false;
// ^? type X = true
type Y = keyof Chimera extends BirdID ? true : false;
// ^? type Y = true