TypeScript:部分“部分”类型

bq9c1y66  于 2023-01-21  发布在  TypeScript
关注(0)|答案(4)|浏览(149)

环境
TypeScript的版本为3.2.1,“tsconfig.json”如下所示。

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "esModuleInterop": true
  }
}

问题

我正在TypeScript中查找部分“部分”类型。

type Entity = {
  a: string,
  b: string,
  c?: string,
};

type Ham = MyType<Entity, 'b'>;
/**
 * expected to equal
 * {
 *   a: string,
 *   b?: string, // changed to be optional
 *   c?: string,
 * };
 */

P.S.提香和汤扬
谢谢你的回复。我检查了你的类型,然后两个类型通过编译器的检查!

const abc = { a: 'a', b: 'b', c: 'c' };
const ab = { a: 'a', b: 'b' };
const ac = { a: 'a', c: 'c' };
const a = { a: 'a' };

// by t7yang
let test1Abc: OptionalKey<Entity, 'b'> = abc;
let test1Ab: OptionalKey<Entity, 'b'> = ab;
let test1Ac: OptionalKey<Entity, 'b'> = ac;
let test1A: OptionalKey<Entity, 'b'> = a;

// by Titian Cernicova-Dragomir    
let test2Abc: PickPartial<Entity, 'b'> = abc;
let test2Ab: PickPartial<Entity, 'b'> = ab;
let test2Ac: PickPartial<Entity, 'b'> = ac;
let test2A: PickPartial<Entity, 'b'> = a;
u7up0aaq

u7up0aaq1#

可以将PickPartial结合使用,只挑选希望设置为可选的属性,同时保留其余属性,使用Exclude获取键,但不包括传入的设置为可选的键:

type Entity = {
   a: string,
   b: string,
   c?: string,
};

type PickPartial<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>> & Partial<Pick<T, K>> 
type Ham = PickPartial<Entity, 'b'>; // a, b? , c?
6tqwzwtp

6tqwzwtp2#

type Entity = {
  a: string,
  b: string,
  c?: string,
};

type OptionalKey<T, O extends keyof T> = Pick<T, Exclude<keyof T, O>> & Partial<{ [P in O]: T[P] }>;

const a: OptionalKey<Entity, 'b'> = {
  a: 'a',
}

const ab: OptionalKey<Entity, 'b'> = {
  a: 'a',
  b: 'b'
}

const ac: OptionalKey<Entity, 'b'> = {
  a: 'a',
  c: 'c'
}

这个想法是挑选所有的属性,要使可选的,然后合并与类型比我们要使属性可选。
你可以在打字场查一下

jw5wzhpr

jw5wzhpr3#

真实的简单的解决方案:

type PickPartial<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
type PartialExcept<T, K extends keyof T> = Pick<T, K> & Partial<Omit<T, K>>;

Titian的解决方案是在Typescript 3.5之前编写的,Typescript 3.5添加了Omit帮助器。
还请记住,您可以使用字符串联合来挑选多个属性,使其成为可选属性:

type Full = {
  a: string;
  b: string;
  c: string;
}

// These are equivalent
type ARequired = PickPartial<Full, 'b' | 'c'>;
type ARequired = PartialExcept<Full, 'a'>;
mrfwxfqh

mrfwxfqh4#

接受答案的简单版本(使用Partial和Pick的交集),没有任何中间类型来混淆事物:

type Entity = {
  a: number,
  b: number,
  c?: number,
}

type Ham = Partial<Entity> & Pick<Entity, Exclude<keyof Entity, 'b'>>;

const b: Ham[] = [{ a: 1 }, { a: 1, b: 1 }, { a: 1, c: 1 }, { a: 1, b: 1, c: 1 }]; // OK.
const c: Ham = {}; // Bad.

Playground

相关问题