Это продолжение этого вопроса 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
будет работают, но почему-то нет.
Есть идеи?