Record
is defined as follows:
/**
* Construct a type with a set of properties K of type T
*/
type Record<K extends keyof any, T> = {
[P in K]: T;
};
It is defined such that for a Record<A, B>
for every A
there is a B
.
But how do I define that there might not be a B
for every A
?
If I use Partial<Record<A, B>>
we would say for every A
there is either B
or undefined
. But I don't want to except undefined
as value:
type A = 'A1' | 'A2' | 'A3';
// Complains about "Type '{ A1: string; }' is missing the following properties from type 'B': A2, A3(2739)"
// But I want to be allowed to ommit any value of A
type B = Record<A, string>;
const fooB: B = {
A1: 'value for A1'
}
// Allows to omit properties but also allows undefined as value, which I don't want.
type C = Partial<Record<A, string>>;
const fooC: C = {
A1: 'value for A1',
A2: undefined // Should not be allowed!
}
( Playground )
To disallow undefined
makes a difference, for example when using Object.keys()
:
Object.keys({A2: undefined})
['A2']
It is still expected and fine that {}.A2 === undefined
.
--exactOptionalPropertyTypes
also can't be used as it would affect the whole codebase (If I am not mistaken also types from external dependencies used).
Record
is defined as follows:
/**
* Construct a type with a set of properties K of type T
*/
type Record<K extends keyof any, T> = {
[P in K]: T;
};
It is defined such that for a Record<A, B>
for every A
there is a B
.
But how do I define that there might not be a B
for every A
?
If I use Partial<Record<A, B>>
we would say for every A
there is either B
or undefined
. But I don't want to except undefined
as value:
type A = 'A1' | 'A2' | 'A3';
// Complains about "Type '{ A1: string; }' is missing the following properties from type 'B': A2, A3(2739)"
// But I want to be allowed to ommit any value of A
type B = Record<A, string>;
const fooB: B = {
A1: 'value for A1'
}
// Allows to omit properties but also allows undefined as value, which I don't want.
type C = Partial<Record<A, string>>;
const fooC: C = {
A1: 'value for A1',
A2: undefined // Should not be allowed!
}
( Playground )
To disallow undefined
makes a difference, for example when using Object.keys()
:
Object.keys({A2: undefined})
['A2']
It is still expected and fine that {}.A2 === undefined
.
--exactOptionalPropertyTypes
also can't be used as it would affect the whole codebase (If I am not mistaken also types from external dependencies used).
1 Answer
Reset to default -1It sounds like you want a type where every A
is explicitly mapped to some output, but the output can be either B
or undefined.
So you would want to use:
Record<A, B|undefined>
Partial<Record<A, B>>
, but you'd need to turn on--exactOptionalPropertyTypes
to prevent the assignment ofundefined
. (Of course you might always readundefined
, because that's what you get when reading missing props, e.g.,({}).a === undefined
.) Does that fully address the question? If so I could write an answer or find a duplicate. If not, what am I missing? – jcalz Commented Feb 3 at 16:36undefined
. Even if it's missing. I don't think what you ask for is possible at the type-system level. It depends on what runtime values you'd be putting in. – VLAZ Commented Feb 10 at 12:16{a: string}
doesn't mean that onlya
can appear. So a value of type {a: string, b: number}` is assignable to{a: string}
, and thus you can't say that{a: string}
has nob
property. If you want to say that, the closest you can get is{a: string, b?: never}
, but that allowsundefined
unless you turn on--exactOptionalPropertyTypes
which you can't/won't do. – jcalz Commented Feb 10 at 13:32