gpt4 book ai didi

TypeScript 与泛型类型的交集,并使用 Partial

转载 作者:行者123 更新时间:2023-12-04 13:51:29 25 4
gpt4 key购买 nike

我有一个非常棘手的 TypeScript 问题,涉及泛型和部分。
这个问题的一个操场是 here
我将使用 React 术语解释这个问题,尽管它与 React 没有直接关系。
有一个自定义的 React 钩子(Hook),它基本上创建了一个 reducer ,使用 useReducer ,它包含一些常见的属性,以及一个通用的 data属性(property)。
让我们假设这是钩子(Hook):

interface IState<T> {
some: string;
data: T;
}

type Action<T> = { type: 'UPDATE_STATE'; payload: Partial<T> };

const foo = <T>(initalState: T) => {
const state: IState<T> = { some: 'foo', data: initalState };
const dispatch = (action: Action<T>) => {
// do something
}

return {state, dispatch};
};
此外,还有另一个自定义钩子(Hook),它实际上扩展了第一个钩子(Hook),通过向 state reducer 添加额外的公共(public)属性:
interface MyBar {
extraData: string;
}

const bar = <T>(initialState: T) => {
const {state, dispatch} = foo<T & MyBar>({ ...initialState, extraData: 'some data' });

return { state, dispatch };
}
现在,一个典型的用法是:
const baz = () => {
const { state, dispatch } = bar<IMyState>({ name: 'mor' });
console.log(state, dispatch)
}
所以在 baz ,我的状态对象将是:
{
"extraData": "some data",
"some": "foo",
"data": {
"name": "mor"
}
}
到现在为止还挺好。现在我想做以下更改:
const bar = <T>(initialState: T) => {
const {state, dispatch} = foo<T & MyBar>({ ...initialState, extraData: 'some data' });

**dispatch({ type: 'UPDATE_STATE', payload: { extraData: 'changed' } });**
return { state, dispatch };
}
我得到:
Type '{ extraData: "changed"; }' is not assignable to type 'Partial<T & MyBar>'.(2322)
input.ts(7, 42): The expected type comes from property 'payload' which is declared here on type 'Action<T & MyBar>'
我不确定为什么会发生这种情况,因为 bar将泛型类型与额外数据一起传递,我希望 foo将能够允许它。
我很感激任何建议!

最佳答案

在这种情况下,TypeScript 无法对可分配性做出任何假设,因为 T不推断为任何类型。它就像一个潘多拉盒子。
考虑这个例子:

interface IState<T> {
some: string;
data: T;
}

type Action<T> = { type: 'UPDATE_STATE'; payload: Partial<T> };

const foo = <T,>(initalState: T) => {
const state = { some: 'foo', data: initalState };
const dispatch = (action: Action<T>) => { }

return { state, dispatch };
};

interface MyBar {
extraData: string;
}

const bar = <T extends Record<string, unknown>,>(initialState: T) => {
const { state, dispatch } = foo({...initialState, extraData: 'some data' });
let x: Partial<T>
let y: { extraData: string; }

x = y // error
y = x // error


// TS is unable to make any assumptions about T
dispatch({ type: 'UPDATE_STATE', payload: { extraData: 's' } })
return { state, dispatch };
}

const baz = () => {
const { state, dispatch } = bar({ name: 'mor', extraData: 's' });
dispatch({ type: 'UPDATE_STATE', payload: { extraData: 's' } })
console.log(state, dispatch)
}
Playground
我说的是这部分代码:
  let x: Partial<T>
let y: { extraData: string; }

x = y // error
y = x // error
x y不可相互分配。如果 T怎么办是这个对象吗 { name: string } - 那么这种行为是不安全的。因为这些对象没有任何共同点。
我知道,当您拨打 bar 时TS 能够推断类型,但请记住我们还没有处于调用阶段。
此外,主要问题在于静态 extraData属性(property)。它还应该使用泛型参数进行参数化。
考虑这个例子:
interface IState<T> {
some: string;
data: T;
}

type Action<T> = { type: 'UPDATE_STATE'; payload: Partial<T> };

const foo = <T,>(initalState: T) => {
const state = { some: 'foo', data: initalState };
const dispatch = (action: Action<T>) => { }
return { state, dispatch };
};

interface MyBar {
extraData: string;
}

const bar = <T, U>(initialState: T, extraData: U) => {
const { state, dispatch } = foo({ ...initialState, ...extraData });

dispatch({ type: 'UPDATE_STATE', payload: { ...extraData } })
return { state, dispatch };
}

const baz = () => {
const { state, dispatch } = bar({ name: 'mor' }, { extraData: 's' });
dispatch({ type: 'UPDATE_STATE', payload: { extraData: 's' } })
console.log(state, dispatch)
}
Playground

关于TypeScript 与泛型类型的交集,并使用 Partial,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69034848/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com