简体   繁体   English

我如何强迫受歧视的工会继续受歧视

[英]How do I force a discriminated union to stay discriminated

I have a object literal type which I am using to dynamically generate forms and I want type-checking to work correctly throughout several different arrays.我有一个 object 文字类型,我用它来动态生成 forms,我希望类型检查在几个不同的 arrays 中正常工作。

export type Intersect<T> = (T extends any ? (x: T) => any : never) extends (
  x: infer R
) => any
  ? R
  : never;
type IndexableKeyTypes = string | number | symbol
type Indexable<T = unknown> = Record<string | number, T>
type JustIndexableTypes<T> = T extends IndexableKeyTypes ? T : never
type IndexableKeys<Rec> = KeysMatching<Rec, IndexableKeyTypes>;

type KeysMatching<Rec, Keys> = NonNullable<
  {
    [RecKey in keyof Rec]: Rec[RecKey] extends Keys ? RecKey : never
  }[keyof Rec]
>

export type GroupBy<T extends Indexable, K extends IndexableKeys<T>> = {
  [KV in JustIndexableTypes<T[K]>]: T extends Record<K, KV> ? T : never
}
export type ValueIntersectionByKeyUnion<T, TKey extends keyof Intersect<T> = keyof Intersect<T>> =
  T extends Record<TKey, any> ? {
    [P in TKey]: T extends Record<P, any> ? (k: T[P]) => void : never;
  }[TKey] extends (k: infer I) => void ? I : never : never;
/* T extends string | number | symbol | Function | undefined | null | Array<any> ? T : */
type KeysAny<T> = T extends any ? { [P in keyof T]: any } : never;
type AllPossibleTypes<T> = NextAllPossibleTypes<{ [K in keyof Intersect<KeysAny<T>>]: ValueIntersectionByKeyUnion<T, K>; }>;
//T[K] extends string | number | symbol | Function | undefined | null | Array<any> ? T[K] :
type NextAllPossibleTypes<T> = { [K in keyof T]?: T[K] extends string | number | symbol | Function | undefined | null | Array<any> ? T[K] : AllPossibleTypes<T[K]> }
type Raise<L extends keyof T[keyof T], T extends Record<string, Record<L, any>>> = { [K in keyof T]: T[K][L] };
type PickField<T, K extends string> = T extends Record<K, any> ? T[K] : never;
type GetFieldAttributesFor<M extends keyof (typeof zschema.models), F extends keyof (typeof zschema.models)[M]["fields"]> = PickField<(typeof zschema.models)[M]["fields"][F], "attributes">;
type GetTableAttributesFor<M extends keyof (typeof zschema.models)> = PickField<(typeof zschema.models)[M], "attributes">;

/** This one works properly */
export type FieldAttributes = {
    [M in keyof (typeof zschema.models)]: {
        [F in keyof (typeof zschema.models)[M]["fields"]]: {
            [I in keyof GetFieldAttributesFor<M, F> & number]: GetFieldAttributesFor<M, F>[I];
        }[keyof GetFieldAttributesFor<M, F> & number]
    }[keyof (typeof zschema.models)[M]["fields"]]
}[keyof (typeof zschema.models)];

/** This doesn't, discriminated types are collapsed */
export type TableAttributes2 = {
    [M in keyof (typeof zschema.models)]: {
        [I in keyof GetTableAttributesFor<M> & number]: {
            key: GetTableAttributesFor<M>[I]["type"];
            val: GetTableAttributesFor<M>[I]["properties"];
        };
    }[keyof GetTableAttributesFor<M> & number]
}[keyof (typeof zschema.models)];

/** The solution, for no discernable reason */
export type TableAttributes1 = {
    [M in keyof (typeof zschema.models)]: {
        [I in keyof GetTableAttributesFor<M> & number]: GetTableAttributesFor<M>[I]
    }[keyof GetTableAttributesFor<M> & number]
}[keyof (typeof zschema.models)];

/** Final working copy for demo purposes */
export type TableAttributes = NextAllPossibleTypes<Raise<"properties",GroupBy<{
    [M in keyof (typeof zschema.models)]: {
        [I in keyof GetTableAttributesFor<M> & number]: GetTableAttributesFor<M>[I]
    }[keyof GetTableAttributesFor<M> & number]
}[keyof (typeof zschema.models)], "type">>>;

declare const zschema: {
  models: {
    "Billing": {
      "name": "Billing",
      "fields": {
        "id": {
          "name": "id",
          "isArray": false,
          "type": "ID",
          "isRequired": true,
          "attributes": []
        },
        "rentalID": {
          "name": "rentalID",
          "isArray": false,
          "type": "ID",
          "isRequired": true,
          "attributes": [
            {
              "type": "index",
              "properties": {
                "name": "byRental"
              }
            }
          ]
        },
        "Amount": {
          "name": "Amount",
          "isArray": false,
          "type": "Float",
          "isRequired": false,
          "attributes": []
        },
        "Date": {
          "name": "Date",
          "isArray": false,
          "type": "AWSDate",
          "isRequired": false,
          "attributes": []
        },
        "Recurrance": {
          "name": "Recurrance",
          "isArray": false,
          "type": "Boolean",
          "isRequired": false,
          "attributes": []
        },
        "LineItems": {
          "name": "LineItems",
          "isArray": true,
          "type": {
            "nonModel": "LineItem"
          },
          "isRequired": false,
          "attributes": [],
          "isArrayNullable": false
        },
        "customerID": {
          "name": "customerID",
          "isArray": false,
          "type": "ID",
          "isRequired": true,
          "attributes": [
            {
              "type": "index",
              "properties": {
                "name": "byCustomer"
              }
            }
          ]
        },
        "PaymentRecord": {
          "name": "PaymentRecord",
          "isArray": false,
          "type": "String",
          "isRequired": false,
          "attributes": []
        },
        "Status": {
          "name": "Status",
          "isArray": false,
          "type": {
            "enum": "BillingStatus"
          },
          "isRequired": false,
          "attributes": []
        },
        "createdAt": {
          "name": "createdAt",
          "isArray": false,
          "type": "AWSDateTime",
          "isRequired": false,
          "attributes": [],
          "isReadOnly": true
        },
        "updatedAt": {
          "name": "updatedAt",
          "isArray": false,
          "type": "AWSDateTime",
          "isRequired": false,
          "attributes": [],
          "isReadOnly": true
        }
      },
      "syncable": true,
      "pluralName": "Billings",
      "attributes": [
        {
          "type": "model",
          "properties": {}
        },
        {
          "type": "key",
          "properties": {
            "name": "byRental",
            "fields": [
              "rentalID"
            ]
          }
        },
        {
          "type": "key",
          "properties": {
            "name": "byCustomer",
            "fields": [
              "customerID"
            ]
          }
        },
        {
          "type": "auth",
          "properties": {
            "rules": [
              {
                "allow": "public",
                "operations": [
                  "create",
                  "update",
                  "delete",
                  "read"
                ]
              }
            ]
          }
        }
      ]
    },
  }
}

The schema data is at the bottom of this code block.模式数据位于此代码块的底部。 You can copy the entire thing into typescript playground.您可以将整个内容复制到 typescript 游乐场。 Yes, I know it's not secure.是的,我知道这不安全。 It's an early stage project.这是一个早期项目。

The code oddly results in both keys being automatically combined into one object, ruining the entire point of discriminated unions.该代码奇怪地导致两个密钥自动组合成一个 object,从而破坏了可区分联合的整个点。 As I've now found a solution, which I included, I'm curious what changed and why.由于我现在已经找到了一个解决方案(包括在内),所以我很好奇发生了什么变化以及为什么发生了变化。

type TableAttributes2 = {
    key: "model" | "auth";
    val: {} | {
        rules: [{
            allow: "public";
            operations: ["create", "update", "delete", "read"];
        }];
    };
}

I have no idea what difference this makes, but this one works properly.我不知道这有什么区别,但这个工作正常。 I changed the value of [I in keyof...] as shown and now it works.如图所示,我更改了[I in keyof...]的值,现在可以使用了。

/** The solution, for no discernable reason */
export type TableAttributes1 = {
    [M in keyof (typeof zschema.models)]: {
        [I in keyof GetTableAttributesFor<M> & number]: GetTableAttributesFor<M>[I]
    }[keyof GetTableAttributesFor<M> & number]
}[keyof (typeof zschema.models)];

/** Final working type */
export type TableAttributes = NextAllPossibleTypes<Raise<"properties",GroupBy<{
    [M in keyof (typeof zschema.models)]: {
        [I in keyof GetTableAttributesFor<M> & number]: GetTableAttributesFor<M>[I]
    }[keyof GetTableAttributesFor<M> & number]
}[keyof (typeof zschema.models)], "type">>>;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM