Ограничение типов TypeScript только разрешенными ключами, т.е. Exact / DeepExact - PullRequest
0 голосов
/ 10 июля 2020

Это продолжение этого вопроса SO , чтобы попытаться имитировать точный тип .

Я думаю, что у меня что-то близкое к DeepExact работает:

// This is the good type/that we want to only accept Exact versions of
type Opts = {
  firstName?: string;
  parent?: string;
  children?: { firstName?: string }[];
};

// This is the incoming type that has unknown fields which should be rejected.
type Args = {
  firstName?: string;
  parentId?: string;
  children?: { firstName?: string; unknownField?: string }[];
};

const a: Args = null!;
// This compiles as expected but I want parentId and children.unknownField to cause type failures
const o: Opts = a;

// function that enforces only the exact Opts type
function onlyOpts<O>(o: Exact<Opts, O>): void {}

// good examples, using known fields
const g1 = { firstName: "f" };
onlyOpts(g1);
const g2 = { parent: "p", children: [{ firstName: "c1" }] };
onlyOpts(g2);

// bad examples, using unknown fields
const b1 = { firstName: "f", parentId: undefined };
onlyOpts(b1); // correctly fails b/c parentId is `never`

const b2 = { firstName: "f", children: [{ firstName: "c1", unknownField: "c1" }] };
onlyOpts(b2); // does not fail but should, unknownField is still `string`

// type alias to show B2["children"][]["unknownField"] is still string
type B2 = Exact<Opts, typeof b2>;

// Prototype Exact/DeepExact
type Exact<T, U> = T &
  {
    [K in keyof U]: K extends keyof T
      ? T[K] extends Array<infer TU>
        ? U[K] extends Array<infer UU>
          ? Array<Exact<TU, UU>>
          : never
        : U[K]
      : never;
  };

Но мой пример b2 не дает сбоев, т.е. глубокая / рекурсивная часть. Тип B2 по-прежнему имеет children с unknownField: string вместо unknownField: never.

Я думал, что отдельный вывод о TU и UU, а затем рекурсивный вывод их в Exact будет работают, но почему-то нет.

Есть идеи?

1 Ответ

0 голосов
/ 10 июля 2020

В настоящее время это работает для большинства моих тривиальных тестовых примеров:

export type Exact<T, U> = T &
  {
    [K in keyof U]: K extends keyof T
      ? T[K] extends Array<infer TU> | undefined | null
        ? U[K] extends Array<infer UU> | undefined | null
          ? Array<Exact<TU, UU>> | undefined | null
          : never
        : U[K]
      : never;
  };

Но не работает в более крупном приложении с большим количеством эзотери c generics / usages / et c. Так что все еще работаю над этим, но я в основном ответил на свой первоначальный вопрос.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...