这是我的第一次尝试:( 游乐场链接)
/** Trigger a compiler error when a value is _not_ an exact type. */
declare const exactType: <T, U extends T>(
draft?: U,
expected?: T
) => T extends U ? T : 1 & 0
declare let a: any[]
declare let b: [number][]
// $ExpectError
exactType(a, b)
Run Code Online (Sandbox Code Playgroud)
小智 7
如果您正在寻找一种不依赖任何第三方库的纯打字稿解决方案,那么这个应该适合您
export function assert<T extends never>() {}
type TypeEqualityGuard<A,B> = Exclude<A,B> | Exclude<B,A>;
Run Code Online (Sandbox Code Playgroud)
和用法就像
assert<TypeEqualityGuard<{var1: string}, {var1:number}>>(); // returns an error
assert<TypeEqualityGuard<{var1: string}, {var1:string}>>(); // no error
Run Code Online (Sandbox Code Playgroud)
啊,类型级相等运算符.@MattMcCutchen提出了一个涉及通用条件类型的解决方案,它可以很好地检测两种类型何时完全相等,而不是相互可分配.在完美的声音类型系统中,"可相互分配"和"相等"可能是相同的,但TypeScript不是完美的声音.特别是,该any类型既是分配到和分配的任何其他类型的,也就是说,string extends any ? true : false和any extends string ? true: false两个评估到true,尽管string和any是不是同一类型.
这是一个IfEquals<T, U, Y, N>评估Yif T和U是否相等的类型,N否则.
type IfEquals<T, U, Y=unknown, N=never> =
(<G>() => G extends T ? 1 : 2) extends
(<G>() => G extends U ? 1 : 2) ? Y : N;
Run Code Online (Sandbox Code Playgroud)
让我们看看它是否有效:
type EQ = IfEquals<any[], [number][], "same", "different">; // "different"
Run Code Online (Sandbox Code Playgroud)
好的,那些被认为是不同的类型.可能存在一些其他边缘情况,其中您认为相同的两种类型被视为不同,反之亦然:
type EQ1 = IfEquals<
{ a: string } & { b: number },
{ a: string, b: number },
"same", "different">; // "different"!
type EQ2 = IfEquals<
{ (): string, (x: string): number },
{ (x: string): number, (): string },
"same", "different">; // "different", as expected, but:
type EQ3 = IfEquals<
{ (): string } & { (x: string): number },
{ (x: string): number } & { (): string },
"same", "different">; // "same"!! but they are not the same,
// intersections of functions are order-dependent
Run Code Online (Sandbox Code Playgroud)
无论如何,给定这种类型我们可以创建一个生成错误的函数,除非这两种类型以这种方式相等:
/** Trigger a compiler error when a value is _not_ an exact type. */
declare const exactType: <T, U>(
draft: T & IfEquals<T, U>,
expected: U & IfEquals<T, U>
) => IfEquals<T, U>
declare let a: any[]
declare let b: [number][]
// $ExpectError
exactType(a, b) // error
Run Code Online (Sandbox Code Playgroud)
每个参数都有一个类型T或U(与泛型参数的类型推断)相交,IfEquals<T, U>因此除非T并且U相等,否则会出现错误.我想,这给了你想要的行为.
请注意,此函数的参数不是可选的.我真的不知道为什么你希望它们是可选的,但是(至少在--strictNullChecks开启时)它会削弱检查:
declare let c: string | undefined
declare let d: string
exactType(c, d) // no error if optional parameters!
Run Code Online (Sandbox Code Playgroud)
如果重要的话,这取决于你.
无论如何希望有所帮助.祝好运!
这是迄今为止我发现的最强大的解决方案:
// prettier-ignore
type Exact<A, B> = (<T>() => T extends A ? 1 : 0) extends (<T>() => T extends B ? 1 : 0)
? (A extends B ? (B extends A ? unknown : never) : never)
: never
/** Fails when `actual` and `expected` have different types. */
declare const exactType: <Actual, Expected>(
actual: Actual & Exact<Actual, Expected>,
expected: Expected & Exact<Actual, Expected>
) => Expected
Run Code Online (Sandbox Code Playgroud)
感谢@jcalz 指出正确的方向!
| 归档时间: |
|
| 查看次数: |
190 次 |
| 最近记录: |