「重学TS 2.0 」TS 练习题第十九题
Opened this issue · 32 comments
实现一个 OptionalKeys
工具类型,用来获取对象类型中声明的可选属性。具体的使用示例如下所示:
type Person = {
id: string;
name: string;
age: number;
from?: string;
speak?: string;
};
type OptionalKeys<T> = // 你的实现代码
type PersonOptionalKeys = OptionalKeys<Person> // "from" | "speak"
提示:该题目有多种解法,感兴趣小伙伴可以自行尝试一下。
请在下面评论你的答案。
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"
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
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"
// 启用 --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 如果没有设置 "strictNullChecks": true 配置项的话,可以想一想应该如何处理。
type OptionalKeys<T> = Exclude<{
[P in keyof T]: T extends T[P] ? never : T[P]
}[keyof T], undefined>
type OptionalKeys<T> = keyof {
[P in keyof T as undefined extends T[P] ? P : never]: T[P]
}
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"
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"
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
// 实现一个 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这些空值
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"
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"
上面感觉没一个对的
type OptionalKeys<T> = {
[P in keyof T]: undefined extends T[P] ? P : never
}[keyof T]
这样也没有报错
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"
export default {}
// 实现一个 OptionalKeys 工具类型,用来获取对象类型中声明的可选属性。具体的使用示例如下所示:
type Person = {
id: string;
name: string;
age: number;
from?: string;
speak?: string;
};
type OptionalKeys = NonNullable<{
[P in keyof T]: undefined extends T[P] ? P : never
}[keyof T]>
type PersonOptionalKeys = OptionalKeys // "from" | "speak"
`
type OptionalKeys = {
[P in keyof T]: {} extends Pick<T, P> ? P : never;
}[keyof T]
`
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"
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
type Person = { ... type PersonOptionalKeys = OptionalKeys<Person> // "from" | "speak"
上面感觉没一个对的
我这显示也是这样。。用在线的 https://typescript-play.js.org/ 会不一样结果。不知道为什么。
tsc --init
然后就正常了。可能有些配置的关系
type Person = {
id: string;
name: string;
age: number;
from?: string;
speak?: string;
};
type OptionalKeys = {
[K in keyof T]: undefined extends T[K] ? K : never;
}[keyof T];
type Filter = T extends undefined ? never : T;
type PersonOptionalKeys = Filter<OptionalKeys> // "from" | "speak"
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]
}
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 = keyof {
[K in keyof T as {} extends Pick<T,K> ? K: never ]: T[K]
} // 你的实现代码
type PersonOptionalKeys = OptionalKeys // "from" | "speak"
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"
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"
就没有人问为啥有个 Undefined 吗?,能有人回答一下吗?
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"
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
时也是可以的
type OptionalKeys<T> = keyof {
[P in keyof T as T[P] extends Required<T>[P] ? never : P]: P;
};
type Person = {
id: string;
name: string;
age: number;
from?: string;
speak?: string;
};
type OptionalKeys = {
[P in keyof T]-?: undefined extends T[P] ? P : never;
}[keyof T];
type PersonOptionalKeys = OptionalKeys; // "from" | "speak"
就没有人问为啥有个 Undefined 吗?,能有人回答一下吗?
type Person = {
id: string;
name: string;
age: number;
from?: string;
speak?: string;
};
type OptionalKeys = {
[P in keyof T]-?: undefined extends T[P] ? P : never;
}[keyof T];
type PersonOptionalKeys = OptionalKeys; // "from" | "speak"