这是我的第一次尝试:(playground link)
/** 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)
答案 0 :(得分:5)
啊,type-level equality operator。 @MattMcCutchen提出了一个solution,涉及泛型条件类型,它在检测两种类型何时完全相等(而不是只能相互赋值)时做得很不错。在完美声音类型的系统中,“相互分配”和“相等”可能是同一回事,但是TypeScript并不是完美声音。特别是,any
类型既可以分配给任何其他类型,也可以从任何其他类型分配,这意味着reduceByKey
和string extends any ? true : false
都求值为any extends string ? true: false
,尽管事实{{1 }}和true
的类型不同。
这是一种string
类型,如果any
和IfEquals<T, U, Y, N>
相等,则求值为Y
,否则为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;
无论如何,给定这种类型,除非这两种类型相等,否则我们可以使函数产生错误:
type EQ = IfEquals<any[], [number][], "same", "different">; // "different"
每个参数的类型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
或/** 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
(用于通用参数的类型推断)与T
相交,因此除非U
和{ {1}}相等。我认为,这给出了您想要的行为。
请注意,此函数的参数不是可选的。我真的不知道为什么您希望它们是可选的,但是(至少在打开IfEquals<T, U>
的情况下)会削弱这样做的检查力:
T
这很重要,取决于您。
无论如何,希望能有所帮助。祝你好运!
答案 1 :(得分:1)
这是到目前为止我发现的最可靠的解决方案:
// 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
感谢@jcalz指出正确的方向!
答案 2 :(得分:0)
迄今为止我见过的最强大的 item: {
timeStamp: new Date(),
description: ''
category: {id: '', categoryName: ''}
}
(虽然仍然不完美)是这个:
expenses.map (expense =>
<Button size="sm" color="secondary" onClick={ () => this.update(expense.id)}>Update</Button>
例如,async update(id) {
// I want to populate the form with the data from expense.id the user clicked on
const response = await fetch(`/api/expenses/${id}`); // GET endpoint from Spring Boot
const body = await response.json();
this.setState( {item: body});
// Handling PUT request
await fetch(`api/expenses/${id}`, {
method: 'PUT',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
}
});
updatedItem = {...this.state.item}; // Getting the updated item
this.setState({item: updatedItem}); // I want to be able to update the state like this
this.props.history.push('/expense');
}
失败。
在这里找到: https://github.com/Microsoft/TypeScript/issues/27024#issuecomment-845655557
答案 3 :(得分:-1)
我们应根据问题采取不同的方法。例如,如果我们知道要与任何数字进行比较,则可以使用typeof()
。
例如,如果我们在比较接口,则可以使用以下方法:
function instanceOfA(object: any): object is A {
return 'member' in object;
}