打字稿:执行一致的对象键类型参数

问题描述:

我有一个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,而不是一个特定的键。

+0

工会类型如何: id:number |串; 看看: https://stackoverflow.com/questions/38628115/what-does-the-pipe-mean-in-typescript – proti

+0

我不知道这有什么帮助:我希望TypeScript只允许'ID:数字“作为参数。 –

+0

哦,好的。虽然不理解你的问题。 – proti

啊,我喜欢这种类型的问题。你遇到的一个问题是,TypeScript不会让你遗漏类型参数和infer their types。你想说一些类似于Column<User>的地方,其中类型参数是从你传递给它的对象字面量推断出来的。好了,我们不能这样做直接......但我们可以间接得到这样的效果:

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

功能columnsFor是不大不小的curried功能;您可以明确设置类型参数,并且它返回另一个函数,该函数接受Column<Row,Field>对象任意有效类型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。现在,您可以继续制作该阵列:

const columns = [ 
    userColumn({ 
    key: "id", 
    render(id: number) { 
     return id; 
    } 
    }), // ok, inferred as Column<User,"id"> 
    userColumn({ 
    key: "name", 
    render(name: string) { 
     return name; 
    } 
    }), // ok, inferred as Column<User,"name"> 
    userColumn({ 
    key: "id", 
    render(id: string) { 
     return id; 
    } 
    }) // error as expected 
]; 

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

+0

谢谢,我怀疑这样做可能是可能的,但我不确定TypeScript中的惯用方法是什么。我希望有一种方法可以保证使用类型系统的正确使用,因为它仍然有可能产生不正确的代码。如果TypeScript通过使'Column'不透明来实现不透明类型,那么所有列都必须使用'columnFor'来创建。 –

+0

你可以使用一个私有构造函数使'Column'成为一个类,并给它一个静态方法来产生所需的'Column'对象。上面的代码并不完全错误;你告诉TypeScript你需要一个'Column '的数组,这实际上不是你的意思。 – jcalz

+0

谢谢,我会看看私人构造函数。至于原始代码没有错误:我认为这个列不是'Column '的有效实例,因为'render'方法不能处理这两种情况。我认为唯一的因为类型检查是由于TypeScript的(不完备的)双变量函数参数。 –