Typescript使用条件类型编写RequiredProps泛型 问题解决方案

问题描述

问题

我试图定义一个通用的sales_date,以便我可以要求接口annual_unqiue_count <> 0上的键SELECT customerID,MONTH(sales_date),SUM(annual_unqiue_count),SUM(sales_volume),(CASE WHEN annual_unqiue_count <> 0 THEN SUM(sales_volume) over (PARTITION BY customerId) ELSE 0 END) AS sales_volume FROM sales GROUP BY 1,2; 不可为空。

例如:

requiredProps<T,K>

应产生类型为K的类型T

解决方

通过反复试验,我可以正常工作:

interface User {
  id: string;
  phoneNumber?: string;
}
type UserWithPhoneNumber = requiredProps<User,'phoneNumber'>

这将导致产生一个等效的类型UserWithPhoneNumber,但是出于可读性考虑,我希望它精确地为{ id: string; phoneNumber: string }

看看type requiredProps<T,K extends keyof T> = { [P in Exclude<keyof T,K>]: T[P]; } & { [P in K]-?: T[P]; }; 中的其他类型,我想可以使用条件类型对其进行修复,但是以下操作无效:

{ name: string } & { phoneNumber: string }

为什么不起作用,如何解决

这里是一个CodeSandBox,可用于: https://codesandbox.io/s/serene-meadow-j20w1?file=/src/index.ts

解决方法

要将对象类型的交集转换为单个类型,可以在其属性上使用标识mapping

type Id<T> = { [K in keyof T]: T[K] };

您可以看到它的行为:

type Test = Id<{ a: string } & { b: number } & { c: boolean }>;
/* type Test = {
    a: string;
    b: number;
    c: boolean;
} */

然后,您可以像这样设置RequiredProps类型的别名:

type RequiredProps<T,K extends keyof T> = 
  Id<Omit<T,K> & Required<Pick<T,K>>>;

让我们验证一下它是否满足您的要求:

type UserWithPhoneNumber = RequiredProps<User,'phoneNumber'>;
/* type UserWithPhoneNumber = {
    id: string;
    phoneNumber: string;
} */

看起来不错。与进来的属性相比,出现的属性可能会被重新排序,这根本不会影响类型兼容性。希望这很好,因为我认为没有什么可以确保它们以相同顺序出现。


关于Omit<T,K>>的字词。从概念上讲,这与您的操作类似,不同之处在于,我使用的是标准库提供的utility types

但是有区别;您的{[P in Exclude<keyof T,K>]: T[P]}不再是同态的 ,因此不会保留T中的属性修饰符。有关同态映射类型如何保留属性修饰符的描述,请参见microsoft/TypeScript#12563。因此,如果您这样做:

type U1 = RequiredPropsV1<User,"id">
/* type U1 = {
    phoneNumber: string | undefined;
} & {
    id: string;
} */
const u1: U1 = { id: "" }; // error! phoneNumber is required

您将看到您的版本最终具有所需的所有属性(但将undefined留在未提及的属性的域中)。想必您会想要更多类似的东西:

type U2 = RequiredProps<User,"id">
/* type U2 = {
    phoneNumber?: string | undefined;
    id: string;
} */
const u2: U2 = { id: "" }; // okay

未提及的属性的必需性不会改变。


无论如何,希望能有所帮助;祝你好运!

Playground link

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...