如果您放弃重载,但仍然想要一个根据参数切换的返回类型,那么您将需要使用generic函数返回一个条件类型。例如:
type CreateDocumentList = <B extends boolean = false>(
options?: { withVersions?: B }
) => B extends true
? DocumentWithVersions[]
: Document[];
这里是泛型类型参数B
is 受约束的 to boolean
and defaults to false
。然后,取决于是否B
is true
or false
,输出是DocumentWithVersions[]
or Document[]
.
返回条件类型的泛型函数的一个警告是,在函数的实现内部,编译器无法验证您所做的事情是否安全。在哪里B
是一个未指定的泛型,编译器defers评估B extends true ? ...
,这意味着它无法看到任何特定值何时与类型匹配。这个痛点是公开问题的主题微软/TypeScript#33912.
const createDocumentListOops: CreateDocumentList = (({
withVersions = false
} = {}) =>
times(
withVersions ? createDocumentWithVersions : createDocument,
chance.natural({ min: 1, max: 10 })
)); // error!
// Type 'Document[]' is not assignable to type
// 'B extends true ? Required<Document>[] : Document[]'
除非采取任何措施来解决这个问题,否则这意味着您将需要使用类型断言或类似的方法以避免实现中的编译器错误:
const createDocumentList = (({
withVersions = false
} = {}) =>
times(
withVersions ? createDocumentWithVersions : createDocument,
chance.natural({ min: 1, max: 10 })
)) as CreateDocumentList; // okay
现在我们可以测试调用createDocumentList()
按照你的意愿行事:
const documentList = createDocumentList({ withVersions: true });
// const documentWithVersionsList: Required<Document>[]
const documentList1 = createDocumentList();
// const documentList1: Document[]
const documentList2 = createDocumentList({ withVersions: false });
// const documentList2: Document[]
const documentList3 = createDocumentList({ withVersions: Math.random() < 0.5 });
// const documentList3: Document[] | Required<Document>[]
看起来不错。注意documentList3
is a union的类型,因为withVersions
输入的属性是boolean
,这是并集true | false
,以及返回类型createDocumentList()
is 分配性的超过工会。这可能是也可能不是您想要的行为,但在我看来这是合理的。
Playground 代码链接