最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

typescript - Type similar to Record<A, B> but saying that not for every A there is a B value (not even an undefine

programmeradmin0浏览0评论

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).

Share Improve this question edited Feb 10 at 13:24 Sebastian Barth asked Feb 3 at 14:45 Sebastian BarthSebastian Barth 4,5517 gold badges44 silver badges66 bronze badges 4
  • 3 You mostly do want Partial<Record<A, B>>, but you'd need to turn on --exactOptionalPropertyTypes to prevent the assignment of undefined. (Of course you might always read undefined, 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:36
  • OK, the edit clarifies things but still - if you have some way to say "my allowed keys are A1 and A2, but I'll only assign A1", then getting a value for A2 would give you undefined. 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
  • 1 Right now the question seems to be overconstrained; I don't see a solution that doesn't loosen or break one of your requirements. TS doesn't let you prohibit properties, only allow them. A type like {a: string} doesn't mean that only a 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 no b property. If you want to say that, the closest you can get is {a: string, b?: never}, but that allows undefined unless you turn on --exactOptionalPropertyTypes which you can't/won't do. – jcalz Commented Feb 10 at 13:32
  • So what will you do with values of this type? Do they get passed to a function? Unless you want to just see an answer of the form "lol no" maybe you can edit to provide more details and use case examples? Like, maybe instead of a specific type, you can accept a generic type which would mean you need a helper function, as shown in this playground link? – jcalz Commented Feb 10 at 14:44
Add a comment  | 

1 Answer 1

Reset to default -1

It 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>

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论