如何使特定类型的所有键都必填,同时保持undefined作为可能的值?

huangapple go评论54阅读模式
英文:

How to make all keys of a type required while keeping undefined as possible value?

问题

我想将类型的键/值映射如下:

  • required_key: string | undefinedrequired_key: string | undefined(相同)
  • required_key: stringrequired_key: string(相同)
  • optional_key?: string | undefinedoptional_key: string | undefined(去除键中的 ?)
  • optional_key?: stringoptional_key: string | undefined(去除键中的 ? 并添加 undefined 作为可能的值)
interface Person {
  firstName: string | undefined;
  middleName?: string;
  lastName?: string | undefined;
}

// 我需要的是:
// interface Person {
//   firstName: string | undefined;
//   middleName: string | undefined;
//   lastName: string | undefined;
// }

type Normalize<T> = { [K in keyof T]-?: T[K] };

// 使用 Normalize<Person> 后得到的结果:
// interface Person {
//   firstName: string | undefined;
//   middleName: string;
//   lastName: string;
// }

const test: Normalize<Person> = {
  firstName: undefined,
  middleName: undefined, // ts 错误,类型为 string,不允许 undefined
  lastName: undefined, // ts 错误,类型为 string,不允许 undefined
};

在 TypeScript 中是否可能实现这个要求?似乎 -? 移除了键和值中的 undefined,但我不知道如何在键是可选的情况下添加 undefined 值选项。

我阅读了这个问题/回答:https://stackoverflow.com/questions/72402413/is-it-possible-to-make-a-property-required-yet-preserve-undefined,我了解到 exactOptionalPropertyTypes 编译器标志,但它仍然没有解决如何将 key?: string 转换为 key: string | undefined

英文:

I want to map key/values of a type as follows:

  • required_key: string | undefined to required_key: string | undefined (same)
  • required_key: string to required_key: string (same)
  • optional_key?: string | undefined to optional_key: string | undefined (removed ? from key)
  • optional_key?: string to optional_key: string | undefined (removed ? from key and added undefined as possible value)
interface Person {
  firstName: string | undefined;
  middleName?: string;
  lastName?: string | undefined;
}

// What I need:
// interface Person {
//   firstName: string | undefined;
//   middleName: string | undefined;
//   lastName: string | undefined;
// }

type Normalize&lt;T&gt; = { [K in keyof T]-?: T[K] };

// What I get with Normalize&lt;Person&gt;:
// interface Person {
//   firstName: string | undefined;
//   middleName: string;
//   lastName: string;
// }

const test: Normalize&lt;Person&gt; = {
  firstName: undefined,
  middleName: undefined, // ts err, type = string, undefined not allowed
  lastName: undefined, // ts err, type = string, undefined not allowed
};

Is it possible in typescript? It seems that -? is removing undefined from both key and value and I don't know how to add undefined value option if key is optional.

I read this Q/A https://stackoverflow.com/questions/72402413/is-it-possible-to-make-a-property-required-yet-preserve-undefined and I know about exactOptionalPropertyTypes compiler flag but it still does not solve how to convert key?: string to key: string | undefined.

答案1

得分: 1

以下是翻译好的部分:

type AllOptionalKeys<T> = { [K in keyof T]-?: undefined extends T[K] ? K : never; }[keyof T];
type AllNonOptionalKeys<T> = { [K in keyof T]-?: undefined extends T[K] ? never : K; }[keyof T];

type Normalize<T> = { [K in AllOptionalKeys<T>]: T[K] | undefined } & { [K in AllNonOptionalKeys<T>]: T[K]; };
英文:

Not sure if this is the best solution, but you can achieve it with the following:

type AllOptionalKeys&lt;T&gt; = { [K in keyof T]-?: undefined extends T[K] ? K : never; }[keyof T];
type AllNonOptionalKeys&lt;T&gt; = { [K in keyof T]-?: undefined extends T[K] ? never : K; }[keyof T];

type Normalize&lt;T&gt; = { [K in AllOptionalKeys&lt;T&gt;]: T[K] | undefined } &amp; { [K in AllNonOptionalKeys&lt;T&gt;]: T[K]; };

The two intermediate types allow to strip the ? from the keys, but keep track of which are optional.

Then it constructs an union type, where all optional keys have a value of T[K] | undefined, and all the non optional keys have T[K].

huangapple
  • 本文由 发表于 2023年2月8日 23:54:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/75388381.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定