TypeScript:强制将一致的对象键作为类型参数

时间:2017-09-15 14:36:16

标签: typescript

我有一个Column接口,可以根据键从行中呈现值:

interface Column<Row, Field extends keyof Row> {
    key: Field;
    render: (value: Row[Field]) => React.ReactNode;
}

如果我明确设置每列的类型,那么我会得到所需的行为。例如,以下内容无效:

interface User {
    id: number;
    name: string;
}

const column: Column<User, "id"> = {
    key: "id",
    render(id: string) {
        return id;
    }
};

因为id属性是字符串,而不是数字。有没有办法获得此行为,而无需单独指定每列的类型?例如,以下类型检查:

const columns: Array<Column<User, keyof User>> = [
    {
        key: "id",
        render(id: string) {
            return id;
        }
    }
];

因为Field被实例化为keyof User,而不是特定的密钥。

1 个答案:

答案 0 :(得分:1)

啊,我喜欢这类问题。您遇到的一个问题是TypeScript不允许您省略类型参数和infer their types。您想说出Column<User>之类的内容,其中Row类型参数是从传递给它的对象文字中推断出来的。好吧,我们不能直接这样做......但我们可以间接地得到这个效果:

function columnsFor<Row>() {
  function of<Field extends keyof Row>(column: Column<Row, Field>): Column<Row, Field> {
    return column;
  }
  return of;
}

函数columnsFor是一种curried函数;您可以显式设置Row类型参数,并返回另一个函数,该函数接受{em>任何有效类型Column<Row,Field>的{​​{1}}对象。以下是您使用它的方式:

Field

const userColumn = columnsFor<User>(); const goodColumn = userColumn({ key: "id", render(id: number) { return id; } }); // ok, inferred as Column<User, "id"> const badColumn = userColumn({ key: "id", render(id: string) { return id; } }); // error as expected 函数只接受某种userColumn类型的参数,并从该参数中推断出Column<User, Field>。现在你可以继续制作那个阵列了:

Field

希望这对你有用。祝你好运!