使用嵌套接口时通用类型丢失

时间:2018-10-02 12:18:54

标签: typescript

我在使用带有“嵌套”接口和ReadonlyArray的泛型时遇到麻烦。如何在不丢失filterList参数类型的情况下运行list函数?

interface INumber {
    value: number
}

interface IState {
    readonly numbers: ReadonlyArray<INumber>
}

var state: IState = {
    numbers: [{ value: 1 }, { value: 2 }, { value: 3 }, { value: 4 }]
} 

function filterList<T>(list: T) {
    return list.filter(x => x.value > 2);
}

// Error: Property 'filter' does not exist on type 'T'.
const res = filterList(state.numbers);

由于使用ReadonlyArray,将filterList函数更改为以下内容将失败。

function filterList(list: INumber[]) {...}

// Error: Argument of type 'ReadonlyArray<INumber>' is not assignable
// to parameter of type 'INumber[]'. Property 'pop' is missing in 
// type 'ReadonlyArray<INumber>'.
const res = filterList(state.numbers);

处理这种情况的最佳实践是什么? 谢谢!

1 个答案:

答案 0 :(得分:1)

您有几种选择。 ReadonlyArray<T>Array的子集,因此我们可以将T包含为具有以下值的某物的ReadonlyArray

var state: IState = {
  numbers: [{ value: 1 }, { value: 2 }, { value: 3 }, { value: 4 }]
} 

function filterList<T extends ReadonlyArray<{value : number }>>(list: T){
  return list.filter(x => x.value > 2);
}

const res = filterList(state.numbers); // ok

var arr = [{ value: 1 }, { value: 2 }, { value: 3 }, { value: 4 }]
const res2 = filterList(arr); //ok

尽管类型参数作为列表并没有太多好处,因为filter将同时返回ReadonlyArrayArray的常规数组,因此可以像好吧:

function filterList<T extends {value : number }>(list: ReadonlyArray<T>){
  return list.filter(x => x.value > 2);
}
const res = filterList(state.numbers); // ok

var arr = [{ value: 1 }, { value: 2 }, { value: 3 }, { value: 4 }]
const res2 = filterList(arr); //ok

如果您希望filterList保留传入的是只读数组还是常规数组,则可以使用第一个版本并返回T,但是您需要使用类型断言来进行filter pe的结果键入为ReadonlyArray

function filterList<T extends ReadonlyArray<{value : number }>>(list: T): T{
  return list.filter(x => x.value > 2) as any;
}

const res = filterList(state.numbers); // ok, res is ReadonlyArray<INumber>

var arr = [{ value: 1 }, { value: 2 }, { value: 3 }, { value: 4 }]
const res2 = filterList(arr); //ok, res s { value: number; }[]