我正在尝试编写一个函数,允许函数的用户使用 no typescript type assertions (只是普通的旧javascript语法)定义某种类型。基本上,我正在尝试编写像React的PropTypes之类的内容,但我想将使用这些“PropTypes”定义的类型映射到可以使用typescript强制执行的类型。
通过查看代码,可能更容易理解我想要做的事情。低于defineFunction
的函数返回一个函数,该函数接收由“PropTypes”定义的对象。
interface PropType<T> { isOptional: PropType<T | undefined> }
type V<Props> = {[K in keyof Props]: PropType<Props[K]>};
interface PropTypes {
string: PropType<string>,
number: PropType<number>,
bool: PropType<boolean>,
shape: <R>(definer: (types: PropTypes) => V<R>) => PropType<R>
}
// the only purpose of this function is to capture the type and map it appropriately
// it does do anything else
function defineFunction<Props, R>(props: (types: PropTypes) => V<Props>, func: (prop: Props) => R) {
return func;
}
// define a function
const myFunction = defineFunction(
// this is the interface definition that will be mapped
// to the actual required props of the function
types => ({
stringParam: types.string,
optionalNumberParam: types.number.isOptional,
objectParam: types.shape(types => ({
nestedParam: types.string,
}))
}),
// this is the function definition. the type of `props`
// is the result of the mapped type above
props => {
props.objectParam.nestedParam
return props.stringParam;
}
);
// use function
myFunction({
stringParam: '',
optionalNumberParam: 0,
objectParam: {
nestedParam: ''
}
});
以下是将鼠标悬停在VS代码中的类型上找到的myFunction
的结果类型:
const myFunction: (prop: {
stringParam: string;
optionalNumberParam: number | undefined;
objectParam: {
nestedParam: string;
};
}) => string
上述代码存在问题 - optionalNumberParam
被正确定义为number | undefined
,但实际上并不是可选的!
如果我省略optionalNumberParam
,那么打字稿编译器就会对我大喊大叫。
T | undefined
?回复cale_b
的评论:
只是一个想法 - 你试过OptionalNumberParam?:types.number.isOptional
是的,语法无效:
为了澄清,这个defineFunction
应该让用户使用 no typescript type assertions 定义一个类型 - 而是应该使用映射类型来推断所有内容。 ?
只是打字稿。我正在尝试编写这个函数,以便 - 理论上 - javascript用户可以定义proptypes并且仍然使用typescript编译器强制执行这些proptypes。
答案 0 :(得分:1)
因此,我能做的最接近的解决方法涉及我提到的双对象文字解决方案:
interface PropType<T> { type: T }
首先我删除了isOptional
,因为它没有用,第二次我添加了一个T
的属性,因为TypeScript不一定能说出PropType<T>
和{{之间的区别1}}如果PropType<U>
和T
不同,除非它们在结构上不同。我认为您不需要使用U
属性。
然后我没碰到一些东西:
type
现在,我正在创建函数type V<Props> = {[K in keyof Props]: PropType<Props[K]>};
interface PropTypes {
string: PropType<string>,
number: PropType<number>,
bool: PropType<boolean>,
shape: <R>(definer: (types: PropTypes) => V<R>) => PropType<R>
}
function defineFunction<Props, R>(props: (types: PropTypes) => V<Props>, func: (prop: Props) => R) {
return func;
}
,它接受类型withPartial
和R
的两个参数,并返回类型O
的值。
R & Partial<O>
让我们试一试:
function withPartial<R, O>(required: R, optional: O): R & Partial<O> {
return Object.assign({}, required, optional);
}
请注意我如何将原始对象文字拆分为两个:一个具有必需属性,另一个具有可选属性,并使用const myFunction = defineFunction(
types => withPartial(
{
stringParam: types.string,
objectParam: types.shape(types => ({
nestedParam: types.string,
}))
},
{
optionalNumberParam: types.number
}
),
props => {
props.objectParam.nestedParam
return props.stringParam;
}
);
函数重新组合它们。另请注意withPartial
的用户不需要使用任何特定于TypeScript的表示法,我认为这是您的要求之一。
检查withPartial()
的类型会给您:
myFunction
这就是你想要的。观察:
const myFunction: (
prop: {
stringParam: string;
objectParam: {
nestedParam: string;
};
optionalNumberParam?: number;
}
) => string
希望有所帮助;祝你好运!