Consider code like this:
const obj = {
a: {x: 1},
b: {x: 2},
};
const bx = obj.b.x; // bx is number
const nx = obj.n.x; // error as expected
but now I want to have more certain type info about obj
, so i do:
const obj = {
a: {x: 1},
b: {x: 2},
} as const;
const bx = obj.b.x; // changed: bx is 2
const nx = obj.n.x; // same: error as expected
until now everythink is ok, but now I need to restrict other team members to patch/add values to obj
in specific general-shape, so:
type GeneralTypeToFollow = { [k in string]: {x: number} }
const obj: GeneralTypeToFollow = {
a: {x: 1},
b: {x: 2},
wrong: 'wrong type', // error as expected
} as const;
const bx = obj.b.x; // changed: bx downgraded to number
const nx = obj.n.x; // changed: nx is number (no error at all)
Restriction now works, but bx
and nx
has lost correct types.
So the expected behavior is:
const bx = obj.b.x; // bx is 2
const nx = obj.n.x; // error
CodePudding user response:
Your only option is to have a generic function. This function can constrain the passed object to GeneralTypeToFollow
and also return the the type of the object literal.
type GeneralTypeToFollow<N extends number> = { [k in string]: { x: N } }
function makeObj<
T extends GeneralTypeToFollow<N>,
N extends number
>(obj: T): T {
return obj
}
const obj = makeObj({
a: { x: 1 },
b: { x: 2 },
});
const bx = obj.b.x; // 2
const nx = obj.n.x; // error
By using the additional generic type N
to represent the numbers, we can also get rid of as const
.