typescript 为什么封装到泛型省略行为与非封装不同?

llmtgqce  于 2023-03-13  发布在  TypeScript
关注(0)|答案(1)|浏览(136)

当我尝试忽略泛型外的属性时,它工作正常,但在泛型内会中断。基本上,问题是Omit<Thing, 'key1' | 'key2'>变成了Omit<Thing, 'key1'> | Omit<Thing, 'key2'>,并且typescript不允许使用Omit<Thing, 'key1'>Omit<Thing, 'key2'>中的偶数键
现场演示: typescript Playground

export class AccessScope {
  id!: number;
  type!: string;
  createdAt!: Date;
  updatedAt!: Date;
}

type KeysWhichShouldBeOmitted = "id" | "createdAt" | "updatedAt";

type AccessScopeWithOmittedId = Pick<AccessScope, "type" | "createdAt" | "updatedAt">;

type OmitIfNotNull<
  Entity,
  Holder,
  KeysToOmit,
> = KeysToOmit extends keyof Entity
  ? Omit<Holder, KeysToOmit>
  : Holder;

type brokenType1 = OmitIfNotNull<
    AccessScope,
    AccessScopeWithOmittedId,
    KeysWhichShouldBeOmitted
>

// Type '{ type: string; }' is not assignable to type 'brokenType1'.
//   Property 'createdAt' is missing in type '{ type: string; }' but required in type 'Omit<Pick<AccessScope, "createdAt" | "updatedAt" | "type">, "updatedAt">'.(2322)
const brokenVar1: brokenType1 = {
    type: 'asd'
}

// brokenType2 is fully visible version of brokenType1
type brokenType2 = Omit<Pick<AccessScope, "type" | "createdAt" | "updatedAt"> & Record<never, never>, "id">
        | Omit<Pick<AccessScope, "type" | "createdAt" | "updatedAt"> & Record<never, never>, "createdAt">
        | Omit<Pick<AccessScope, "type" | "createdAt" | "updatedAt"> & Record<never, never>, "updatedAt">

// Type '{ type: string; }' is not assignable to type 'brokenType1'.
//   Property 'createdAt' is missing in type '{ type: string; }' but required in type 'Omit<Pick<AccessScope, "createdAt" | "updatedAt" | "type">, "updatedAt">'.(2322)
const brokenVar2: brokenType2 = {
    type: 'asd'
}

type normalType = KeysWhichShouldBeOmitted extends keyof AccessScope
  ? Omit<AccessScopeWithOmittedId, KeysWhichShouldBeOmitted>
  : AccessScopeWithOmittedId

const normalType: normalType = {
    type: 'asd'
}

我尝试添加了扩展OmitIfNotNull参数的各种奇怪变体

type OmitIfNotNull<
  Entity extends Holder,
  Holder extends Record<string, any>,
  KeysToOmit extends keyof Entity,
> = KeysToOmit extends keyof Entity
  ? Omit<Holder, KeysToOmit>
  : Holder;
gblwokeq

gblwokeq1#

此行为是由条件类型的分布特性引起的。您可以通过将extends子句的两侧括在方括号中来禁用此行为:

export class AccessScope {
  id!: number;
  type!: string;
  createdAt!: Date;
  updatedAt!: Date;
}

type KeysWhichShouldBeOmitted = "id" | "createdAt" | "updatedAt";

type AccessScopeWithOmittedId = Pick<AccessScope,
                                     "type" | "createdAt" | "updatedAt">;

type OmitIfNotNull<
  Entity,
  Holder,
  KeysToOmit,
> = [KeysToOmit] extends [keyof Entity]
  ? Omit<Holder, KeysToOmit>
  : Holder;

type noLongerBrokenType = OmitIfNotNull<
    AccessScope,
    AccessScopeWithOmittedId,
    KeysWhichShouldBeOmitted
>

const noLongerBrokenVar: noLongerBrokenType = {
    type: 'asd'
}

Playground链接

相关问题