awesome-typescript icon indicating copy to clipboard operation
awesome-typescript copied to clipboard

「重学TS 2.0 」TS 练习题第十九题

Open semlinker opened this issue 4 years ago • 33 comments

实现一个 OptionalKeys 工具类型,用来获取对象类型中声明的可选属性。具体的使用示例如下所示:

type Person = {
  id: string;
  name: string;
  age: number;
  from?: string;
  speak?: string;
};

type OptionalKeys<T> = // 你的实现代码
type PersonOptionalKeys = OptionalKeys<Person> // "from" | "speak"

提示:该题目有多种解法,感兴趣小伙伴可以自行尝试一下。 请在下面评论你的答案。

semlinker avatar Sep 17 '21 14:09 semlinker

type Person = {
  id: string;
  name: string;
  age: number;
  from?: string;
  speak?: string;
};

type OptionalKeys<T> = NonNullable<{
  [P in keyof T]: undefined extends T[P] ? P : never
}[keyof T]>

type PersonOptionalKeys = OptionalKeys<Person> // "from" | "speak"

douhao1988 avatar Sep 17 '21 15:09 douhao1988

type Person = {
  id: string;
  name: string;
  age: number;
  from?: string;
  speak?: string;
};

type OptionalKeys<T> = Exclude<
  {
    [K in keyof T]: undefined extends T[K] ? K : never;
  }[keyof T],
  undefined
>;

type PersonOptionalKeys = OptionalKeys<Person>; // "from" | "speak

zhaoxiongfei avatar Sep 18 '21 00:09 zhaoxiongfei

type Undefined<T> = { [P in keyof T]: P extends undefined ? T[P] : never }

type ConditionPickKey<T, Condition> = {
  [Key in keyof T]: T[Key] extends Condition ? Key : never
}

type OptionalKeys<T> = Exclude<keyof T, NonNullable<ConditionPickKey<Undefined<T>, never>[keyof T]>>

interface Something {
  a: undefined  // special test case
  b: string
  phone?: string
}
type AllOptionalKeys = OptionalKeys<Something> // "phone"

869288142 avatar Sep 19 '21 05:09 869288142

// 启用 --strictNullchecks 即在tsconfig.js中设置"strictNullChecks": true
type Person = {
  id: string;
  name: string;
  age: number;
  from?: string;
  speak?: string;
};

type OptionalKeys<T> = {
    [p in keyof T]: undefined extends T[p] ? p : never
}[keyof T]// 你的实现代码
type PersonOptionalKeys = OptionalKeys<Person> // "from" | "speak"

mingzhans avatar Sep 22 '21 12:09 mingzhans

@mingzhans 如果没有设置 "strictNullChecks": true 配置项的话,可以想一想应该如何处理。

semlinker avatar Sep 22 '21 13:09 semlinker

type OptionalKeys<T> = Exclude<{
    [P in keyof T]: T extends T[P] ? never : T[P]
}[keyof T], undefined>

xwnwho avatar Sep 23 '21 07:09 xwnwho

  type OptionalKeys<T> = keyof {
    [P in keyof T as undefined extends T[P] ? P : never]: T[P]
  }

ln0y avatar Sep 23 '21 10:09 ln0y

type Person = {
  id: string;
  name: string;
  age: number;
  from?: string;
  speak?: string;
};

type OptionalKeys<T> = NonNullable<
  {
    [K in keyof T]: undefined extends T[K] ? K : never;
  }[keyof T]
>;

type PersonOptionalKeys = OptionalKeys<Person>; // "from" | "speak"


wenye123 avatar Sep 24 '21 07:09 wenye123

type Person = {
  id: string;
  name: string;
  age: number;
  from?: string;
  speak?: string;
};
type partical<T> = {
  [x in keyof T]?: T[x]
}

type OptionalKeys<T> = 
keyof
{
  [x in keyof T as partical<T>[x] extends T[x] ? x : never]: T[x] 
}

type PersonOptionalKeys = OptionalKeys<Person> // "from" | "speak"

tenderjk avatar Sep 28 '21 09:09 tenderjk

type Person = {
  id: string;
  name: string;
  age: number;
  from?: string;
  speak?: string;
};

type OptionalKeys<T> = // 你的实现代码
type PersonOptionalKeys = OptionalKeys<Person> // "from" | "speak"
type OptionalKeys<T> = {
  [P in keyof T]: (undefined extends T[P] ? P : never)
}[keyof T] & keyof T

winfa avatar Sep 28 '21 16:09 winfa

// 实现一个 OptionalKeys 工具类型,用来获取对象类型中声明的可选属性。具体的使用示例如下所示:

type Person = {
  id: string;
  name: string;
  age: number;
  from?: string;
  speak?: string;
};

type IsEqual<T, U> = [T] extends [U] ? [U] extends [T] ? true : false : false;

type OptionalKeys<T> = NonNullable<{
  [k in keyof T]: IsEqual<Pick<T, k>, Partial<Pick<T, k>>> extends true ? k : never;
}[keyof T]>

type PersonOptionalKeys = OptionalKeys<Person> // "from" | "speak"

解题思路: 本题在严格模式下较难,利用在迭代的过程中利用 Pick 构造单一属性的类型,之后去和只读的去全IsEqual的比较。相同则证明是只读类型,保留,否则返回never,最后利用 [keyof T] 读取所有的值的联合类型。 我没考清楚为啥会有undefined,最后通过NonNullable去掉undefined, null这些空值

zhaoxiongfei avatar Oct 02 '21 06:10 zhaoxiongfei

type Person = {
    id: string;
    name: string;
    age: number;
    from?: string;
    speak?: string;
};

type OptionalKeys<T> = {
    [P in keyof T]-?: undefined extends T[P] ? P : never
}[keyof T]

// 测试用例
type PersonOptionalKeys = OptionalKeys<Person> // "from" | "speak"

Mrlgm avatar Oct 02 '21 15:10 Mrlgm

image 你们很多答案都是这个结果,只有我是这样吗

pagnkelly avatar Oct 08 '21 07:10 pagnkelly

type Person = {
  id: string;
  name: string;
  age: number;
  from?: string;
  speak?: string;
};

type OptionalKeys<T> = {
  [P in keyof T]: Pick<T, P> extends Required<Pick<T, P>> ? never : P
}[keyof T]

type PersonOptionalKeys = OptionalKeys<Person> // "from" | "speak"

上面感觉没一个对的

pagnkelly avatar Oct 08 '21 11:10 pagnkelly

type OptionalKeys<T> = {
  [P in keyof T]: undefined extends T[P] ? P : never
}[keyof T]

这样也没有报错

jerry-f avatar Oct 31 '21 02:10 jerry-f

type Person = {
  id: string;
  name: string;
  age: number;
  from?: string;
  speak?: string;
};

type OptionalKeys<T> = {
  [K in keyof T]: {} extends Pick<T, K> ? K : never;
}[keyof T];

type PersonOptionalKeys = OptionalKeys<Person>; // "from" | "speak"

towavephone avatar Nov 30 '21 06:11 towavephone

export default {}

// 实现一个 OptionalKeys 工具类型,用来获取对象类型中声明的可选属性。具体的使用示例如下所示: type Person = { id: string; name: string; age: number; from?: string; speak?: string; };

type OptionalKeys<T> = NonNullable<{ [P in keyof T]: undefined extends T[P] ? P : never }[keyof T]> type PersonOptionalKeys = OptionalKeys<Person> // "from" | "speak"

a572251465 avatar Dec 01 '21 23:12 a572251465

` type OptionalKeys<T> = { [P in keyof T]: {} extends Pick<T, P> ? P : never; }[keyof T]

`

liulise avatar Dec 07 '21 10:12 liulise

type Person = {
  id: string;
  name: string;
  age: number;
  from?: string;
  speak?: string;
};

type OptionalKeys<T> = { [P in keyof T]-?: undefined extends T[P] ? P : never }[keyof T];
type PersonOptionalKeys = OptionalKeys<Person> // "from" | "speak"

Ljp10086 avatar Dec 31 '21 08:12 Ljp10086

type Person = {
  id: string;
  name: string;
  age: number;
  from?: string;
  speak?: string;
};

type OptionalKeys<T> = {
  [P in keyof T]: Pick<T, P> extends Required<Pick<T, P>> ? never : P
}[keyof T]

type PersonOptionalKeys = OptionalKeys<Person> // "from" | "speak"

上面感觉没一个对的

我用你的这个得到的是: "from" | "speak" | undefined

ihoneys avatar Jan 19 '22 09:01 ihoneys

type Person = {
...
type PersonOptionalKeys = OptionalKeys<Person> // "from" | "speak"

上面感觉没一个对的

我这显示也是这样。。用在线的 https://typescript-play.js.org/ 会不一样结果。不知道为什么。


tsc --init 然后就正常了。可能有些配置的关系

wgf4242 avatar Jan 19 '22 12:01 wgf4242

type Person = { id: string; name: string; age: number; from?: string; speak?: string; };

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

type Filter<T> = T extends undefined ? never : T;

type PersonOptionalKeys = Filter<OptionalKeys<Person>> // "from" | "speak"

Young-zhiqiang avatar Mar 13 '22 10:03 Young-zhiqiang

type Person = {
  id: string;
  name: string;
  age: number;
  from?: string;
  speak?: string;
};


type PersonOptionalKeys = OptionalKeys<Person> // "from" | "speak"

type OptionalKeys<T> = keyof {
  [K in keyof T as T[K] extends Exclude<T[K], undefined> ? never : K]: T[K]
}

补充:

//判断条件放在右侧里
type OptionalKeys1<T> = Exclude<{
   [P in keyof T]: undefined extends T[P] ? P : never
}[keyof T], undefined>
// 第一版的改造,NonNullable工具类型去掉联合类型中的undefined|null
type OptionalKeys2<T> = keyof{
  [K in keyof T as T[K] extends NonNullable<T[K]> ? never : K]: T[K]
}

waleiwalei avatar Mar 15 '22 03:03 waleiwalei

type Person = { id: undefined; name: string; age: number; from?: string; speak?: string; };

type C = { name:string,age:string} extends { name:string }?true:false; type OptionalKeys<T> = keyof { [K in keyof T as {} extends Pick<T,K> ? K: never ]: T[K] } // 你的实现代码 type PersonOptionalKeys = OptionalKeys<Person> // "from" | "speak"

edisonLzy avatar Jun 06 '22 08:06 edisonLzy

type Person = {
  id: string;
  name: string;
  age: number;
  from?: string;
  speak?: string;
};

type OptionalKeys<T> = keyof {
    [P in keyof T as undefined extends T[P] ? P : never] :T[P]
}
type PersonOptionalKeys = OptionalKeys<Person> // "from" | "speak"

dentm avatar Jun 27 '22 05:06 dentm

type Person = {
    id: string;
    name: string;
    age: number;
    from?: string;
    speak?: string;
};
type OptionalKeys<T> = NonNullable<
{
    [K in keyof T]: T extends Record<K, T[K]> ? never : K;
}[keyof T]>// 你的实现代码
type PersonOptionalKeys = OptionalKeys<Person> // "from" | "speak"

dingzc2450 avatar Jul 21 '22 01:07 dingzc2450

就没有人问为啥有个 Undefined 吗?,能有人回答一下吗?

zhengyimeng avatar Nov 11 '22 01:11 zhengyimeng

type Person = { id: string; name: string; age: number; from?: string; speak?: string; }; type OptionalKeys <T> ={[K in keyof T]: T extends Record<K, T[K]> ? never : K}[keyof T]; type PersonOptionalKeys = OptionalKeys<Person> // "from" | "speak"

nanjingcaiyong avatar Sep 18 '23 03:09 nanjingcaiyong

type IsEqual<T, U> = [T] extends [U] ? [U] extends [T] ? true : false : false;

type OptionalKeys<T> = {
  [k in keyof T]: IsEqual<Pick<T, k>, Partial<Pick<T, k>>> extends true ? k : never;
}[keyof T]

这种在设置 strictNullChecks = false时也是可以的

SweeperDuan avatar Dec 12 '23 03:12 SweeperDuan

type OptionalKeys<T> = keyof {
	[P in keyof T as T[P] extends Required<T>[P] ? never : P]: P;
};

JustWantToHappy avatar Feb 13 '24 14:02 JustWantToHappy