版本:打字稿3和React 16。
我想传递自定义属性,并允许覆盖组件上的所有标准HTML属性。
组件使用情况:
<ExamplePropTransfer specialProp={"test"} style={{color:'blue'}}/>
ExamplePropTransfer:
import * as React from "react"
import {HTMLProps, PureComponent} from "react";
export interface ExampleProps{
specialProp: string;
// and possibly many more
}
export class ExamplePropTransfer
extends PureComponent<ExampleProps & HTMLProps<HTMLSpanElement>> {
render(){
console.log("specialProp: " + this.props.specialProp);
// (A)
// warning.js:33 Warning: React does not recognize the
// `specialProp` prop on a DOM element.
// return <span {...(this.props as HTMLProps<HTMLSpanElement>)}>
// Example Content
// </span>
// (B)
let {specialProp, ...htmlProps} = this.props;
return <span {...htmlProps}>Example Content</span>
}
}
我能够完成这项工作的唯一方法是上面的示例代码中的(B)。
但这很容易出错,因为我在重复自己。每当我在ExampleProps
中添加/删除成员时,我都必须维护解构语句。
整个破坏性陈述是多余的。我不需要引用各个属性-我只是在剥离我的自定义属性,以使它们不会作为span
属性传递。
我尝试执行(A),但仍然将specialProps
传递到span
并导致React
记录上面的警告。
我正试图告诉Typescript“从{.1}定义的属性中转移出this.props的所有属性” 而不必明确列出它们?
答案 0 :(得分:1)
除非使用元数据反射,否则接口在运行时不存在,因此无法在运行时“传输除ExampleProps
上定义的那些属性以外的所有属性”。我不熟悉元数据反射的示例,但是这是一种替代方法,它可以为您提供ExampleProps
类型,并且可以在运行时删除道具而无需重复自己:
import * as React from "react"
import {HTMLProps, PureComponent} from "react";
import _ from "underscore";
type Placeholder<T> = {placeholder: T};
function p<T>() { return {} as Placeholder<T>; }
const examplePropsSpec = {
specialProp: p<string>()
};
export type ExampleProps = {
[K in keyof typeof examplePropsSpec]:
(typeof examplePropsSpec)[K] extends Placeholder<infer T> ? T : never;
};
export class ExamplePropTransfer
extends PureComponent<ExampleProps & HTMLProps<HTMLSpanElement>> {
render(){
console.log("specialProp: " + this.props.specialProp);
let htmlProps = _.omit(this.props, Object.keys(examplePropsSpec));
return <span {...htmlProps}>Example Content</span>
}
}
答案 1 :(得分:0)
马特的答案非常棒,但我认为可以将其简化一点(不需要占位符类型):
coverageIstanbulReporter: {
dir: require('path').join(__dirname, '../coverage'),
reports: ['html', 'lcovonly'],
fixWebpackSourcePaths: true
}
答案 2 :(得分:0)
如果我们希望TypeScript接口在运行时不使用反射而存在,则可以使用对象文字来保存该接口中的成员来创建它。它很脆弱,但是编译器会告诉我们接口是否已更改,以便我们可以调整接口对象。
然后,我们可以过滤对象以仅保留其属性,即接口中的键。
POC:
// @types/react/index.d.ts
interface HTMLProps<T> {
accept?: string;
acceptCharset?: string;
action?: string;
// ... see https://github.com/DefinitelyTyped/DefinitelyTyped/blob/10a19353e01f9cd275d4efda9be386c3dc7d6115/types/react/index.d.ts
}
// Our code
type Required<T> = {
[P in keyof T]: T[P];
}
const allHTMLProps: Required<HTMLProps<any>> = {
accept: '',
acceptCharset: '',
action: ''
// ...
};
const allHTMLPropsKeys = Object.keys(allHTMLProps);
function filterHTMLProps<P, O>(o: O & HTMLProps<T>) {
const result: HTMLProps<T> = {};
Object.keys(o).forEach(k => {
if (allHTMLPropsKeys.indexOf(k) >= 0) {
result[k] = o[k];
}
});
return result;
}
const source = { accept: 'a', ko: 1 };
console.log(filterHTMLProps(source)); // { accept: 'a' }