![](/img/trans.png)
[英]TypeScript: Why can't I access a property on a Union Type which is only defined on one object?
[英]Why can't I assign a typescript generic type to a union of that type?
我的一个网络应用程序中有以下类型:
import React, {FC} from 'react';
import { Table, Tbody, Td, Th, Thead, Tr, chakra } from '@chakra-ui/react';
import { TriangleDownIcon, TriangleUpIcon } from '@chakra-ui/icons'
import {useTable, useSortBy, Column} from 'react-table'
import {Adult, Child} from "~/src/types/models";
type PersonTablePropData =
| {
persons: Adult[]
columns: readonly Column<Adult>[]
}
| {
persons: Child[]
columns: readonly Column<Child>[]
}
export type PersonTableProps = PersonTablePropData & {
showPerson: (personId: number) => void
}
const PersonTable: FC<PersonTableProps> = ({ persons, showPerson, columns }) => {
const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } =
useTable<Adult|Child>({ columns, data: persons }, useSortBy)
...
这会导致最后一行的“列”出现错误:
Type 'readonly Column<Adult>[] | readonly Column<Child>[]' is not assignable to type 'readonly Column<Adult | Child>[]'.
这让我有点不知所措:不应该将readonly Column<Adult>[]
分配给readonly Column<Adult | Child>[]
readonly Column<Adult | Child>[]
? 据我所知,这将是一个直接的子集,那么这里出了什么问题?
这让我有点不知所措:不应该将只读 Column[] 分配给只读 Column<Adult | 孩子>[]? 据我所知,这将是一个直接的子集,那么这里出了什么问题?
你是绝对正确的。 在正常情况下它应该是可分配的。
type Adult = {
tag: 'Adult',
name: string,
age: number
}
type Child = {
tag: 'Child',
school: number
}
let adult: Adult[] = []
let both: Array<Child | Adult> = []
both = adult // ok,
adult = both // error, as expected
但是,对于函数参数,情况并非如此。 剧透:逆变。
let adultFn = (arg: Adult[]) => { }
let bothFn = (arg: Array<Child | Adult>) => { }
bothFn = adultFn // error
adultFn = bothFn // ok
adult
不再可分配给bothFn
。 继承的箭头朝相反的方向改变。
让我们更接近您的示例:
type Adult = {
tag: 'Adult',
name: string,
age: number
}
type Child = {
tag: 'Child',
school: number
}
type Options<T> = {
columns: T[],
handler: (arg: T) => void
}
let adult: Adult[] | Child[] = []
let hook = <T,>(arg: Options<T>) => { }
// same error as you have
hook<Adult | Child>({ columns: adult })
正如您可能已经注意到的那样,此错误与您的错误相同。 现在,尝试从Options<T>
类型中删除handler: (arg: T) => void
。 错误将消失。 为什么 ? 因为逆变。 这就是使您的代码更安全的原因。 useTable
钩子在引擎盖下使用UseTableOptions
类型,其中提供的泛型D
用于逆变位置 - 在参数位置。
type UseTableOptions<D extends object> = {
columns: ReadonlyArray<Column<D>>;
data: readonly D[];
} & Partial<{
initialState: Partial<TableState<D>>;
stateReducer: (newState: TableState<D>, action: ActionType, previousState: TableState<D>, instance?: TableInstance<D>) => TableState<D>;
useControlledState: (state: TableState<D>, meta: Meta<D>) => TableState<D>;
defaultColumn: Partial<Column<D>>;
getSubRows: (originalRow: D, relativeIndex: number) => D[];
getRowId: (originalRow: D, relativeIndex: number, parent?: Row<D>) => string;
autoResetHiddenColumns: boolean;
}>
请看另一个简化示例:
type Options<T> = {
handler: (arg: T) => void
}
type SuperType = string;
type SubType = 'hello'
declare let superType: SuperType;
declare let subType: SubType;
superType = subType // ok
subType = superType // error
let superTypeObj: Options<SuperType> = {
handler: (arg) => { }
}
let subTypeObj: Options<SubType> = {
handler: (arg) => { }
}
// opposite direction
superTypeObj = subTypeObj // error
subTypeObj = superTypeObj // ok
发生这种情况是因为您试图将作为数组的类型Adult[]分配给不是数组类型的类型Adult 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.