我希望组件公开接受类型的常量对象(即枚举)的函数.假设这个型号是Test.

如果该函数接受Record<string, Test>,则名称和Test个对象之间的关系将丢失.但是,如果您try 传递一个带有额外字段的对象,编译器将抛出TS2345

如果函数将接受泛型参数Textends Record<string, Test>,则关系将被保存,但额外的字段不会再导致编译错误.

如果这是其他人使用的库方法,它将掩盖库用户因拼写错误而导致的全部错误.

在这两者之间有没有什么我怀念的 Select ?

type Test = {
  field: number
}

function a(param: Record<string, Test>) {
  return param;
}

function b<T extends Record<string, Test>>(param: T) {
  return param;
}

const x = a({
  first: {
    field:     13,
    notExists: -1, // TS2345:  Object literal may only specify known properties, and not_exists does not exist in type Test
  },
} as const);

const y = b({
  first: {
    field:     42,
    notExists: -1, // I want this line to throw compile-time error
  },
} as const);

type xa = typeof x['first']['field']; // number
type xb = typeof y['first']['field']; // 42

// And keep finding 42 instead of number in type above

推荐答案

请考虑以下示例:

type Test = {
  field: number
}

function a(param: Record<string, Test>) {
  return param;
}

type Validation<T extends Record<string, Test>> = {
  [Prop in keyof T]: {
    /**
     * Iterate through keys of root properties
     * If a Key dont extends 'field' it means that it is anvialid key
     * and we can assign 'never' type to it so it will be unrepresentable
     */
    [Key in keyof T[Prop]]: Key extends 'field' ? T[Prop][Key] : never
  }
}
const b = <
  const Field extends Test,
  T extends Record<string, Field>
>(param: Validation<T>) => param

const x = b({
  first: {
    field: 13,
    notExists: -1, // TS2345:  Object literal may only specify known properties, and not_exists does not exist in type Test
  },
});


type xb = typeof x['first']['field'] // 13

Playground

您需要遍历测试对象类型,并将never赋给每个非field键.

例如,如果类型测试={a:number;b:number}|{c:number,d:number},则这将不起作用

请考虑以下几点:

// taken from here https://stackoverflow.com/questions/65805600/type-union-not-checking-for-excess-properties#answer-65805753
type UnionKeys<T> = T extends T ? keyof T : never;
type StrictUnionHelper<T, TAll> =
  T extends any
  ? T & Partial<Record<Exclude<UnionKeys<TAll>, keyof T>, never>> : never;

type StrictUnion<T> = StrictUnionHelper<T, T>

type Test = StrictUnion<{ a: number; b: number } | { c: number, d: number }>

const b = <
  const Field extends Test,
  T extends Record<string, Field>
>(param: T) => param

const x = b({
  first: {
    a: 1,
    b: 1,
  },
});


type xb = typeof x['first']['a'] // 1


Playground

Typescript相关问答推荐

为什么在TypScript中写入typeof someArray[number]有效?

使用Angular和API请求在CRUD操作后更新客户端数据的良好实践

React typescribe Jest调用函数

异步动态生成Playwright测试,显示未找到测试

泛型函数中输入参数类型的推断问题

Angular 信号:当输入信号改变值时,S触发取数的正确方式是什么?

如何使用Zod使一个基于其他字段值的字段为必填字段?

如何使用WebStorm调试NextJS的TypeScrip服务器端代码?

如何调整对象 struct 复杂的脚本函数的泛型类型?

一个打字类型可以实现一个接口吗?

刷新时保持当前名称的Angular

是否可以强制静态方法将同一类型的对象返回其自己的类?

将超类型断言为类型脚本中的泛型参数

如何从JWT Reaction中提取特定值

我可以将一个类型数组映射到TypeScrip中的另一个类型数组吗?

完全在类型系统中构建的东西意味着什么?

有没有一种方法可以提升对象的泛型级别,而对象的值是泛型函数?

通过函数传递确切的类型,但验证额外的字段

JSX.Element';不可分配给类型';ReactNode';React功能HOC

在 next.js 13.4 中为react-email-editor使用forwardRef和next/dynamic的正确方法