我需要创建多个测试,并且要确保设置类型正确。我正在阅读Generics文档,虽然我能理解一些简单的案例,但对高级示例却迷失了。
我尝试做类似于上一个示例中的here。
有两个测试函数签名,它们随测试值和条件值的不同而变化:
interface ITestFuncWithCond<ValueType, ConditionType> {
(value: ValueType, condition: ConditionType): boolean;
};
interface ITestFuncNoCond<ValueType> {
(value: ValueType): boolean;
};
想法是对测试做类似的事情(注意类型):
// Example A
// No condition param
const testA: Tester = createTest(StringTestIsEmpty);
// Value param type must be string.
testA.test("myString");
// Example B
// condition param is number
const testB: Tester = createTest(StringLengthEquals, 2);
// Value param type must be string.
testB.test("myString");
// Example C
// condition param is string
const testC: Tester = createTest(StringEquals, "myString");
// Value param type must be string.
testC.test("myString");
// Example D
// condition param is number
const testD: Tester = createTest(NumberEquals, 10);
// Value param type must be number.
testD.test(5);
这是我为此所用的伪代码,但是正如您可能会看到的,我需要一些指导性术语来对此进行整理。
我更新了以下代码,以尝试更好地解释我要查找的内容。 Here's a sandbox
// Test implementations
const _StringTestIsEmpty = (x: string): boolean => {
console.log(x);
return x === "";
}
const _StringLengthEquals = (x: string, l: number): boolean => {
console.log(x, l);
return x.length === l;
}
const _StringEquals = (x: string, y: string): boolean => {
console.log(x, y);
return x === y;
}
const _NumberEquals = (x: number, y: number): boolean => {
console.log(x, y);
return x === y;
}
// Different tests available
enum TestName {
StringTestIsEmpty,
StringLengthEquals,
StringEquals,
NumberEquals
}
// Test signatures.
interface ITestFuncWithCond<ValueType, ConditionType> {
(value: ValueType, condition: ConditionType): boolean;
};
interface ITestFuncNoCond<ValueType> {
(value: ValueType): boolean;
};
class Tester<ConditionType, ValueType> {
name: TestName;
condition?: ConditionType;
// ValueType??? ConditionType ???
private testFunction: ITestFuncWithCond<ValueType, ConditionType> | ITestFuncNoCond<ValueType>
// Test constructor with different signatures.
constructor(testName: TestName);
constructor(testName: TestName, condition: ConditionType);
constructor(testName: TestName, condition?: ConditionType) {
this.name = testName;
this.condition = condition;
// Here, the testName is used to fetch the actual test function (testImpl)
this.testFunction = this.getFunction(testName)
}
// ValueType should be string for test A, B and C, and should be number for test D.
// "this.condition" should be undefined in test A.
// "this.condition" should be "number for test B and D, and "string" for testC.
test(value: ValueType): boolean {
if (this.condition) {
return this.testFunction(value, this.condition);
} else {
return this.testFunction(value);
}
}
private fetchTestFunction<V, C extends [] | [condition: any]>(iTestFunc: (value: V, ...conditionMaybe: C) => boolean, ...conditionMaybe: C) {
return {
test: (v: V) => iTestFunc(v, ...conditionMaybe)
}
}
private getFunction(testName: TestName) {
switch (testName) {
case TestName.StringTestIsEmpty: {
return this.fetchTestFunction(_StringTestIsEmpty);
}
case TestName.StringLengthEquals: {
return this.fetchTestFunction(_StringLengthEquals, this.condition);
}
case TestName.StringEquals: {
return this.fetchTestFunction(_StringEquals, this.condition);
}
case TestName.NumberEquals: {
return this.fetchTestFunction(_NumberEquals, this.condition);
}
}
}
}
function createTest(testName: TestName, condition?: any): Tester {
// set up to properly fetch the right test
return new Tester(testName, condition);
}
// Example A
// No condition param
// don't annotate Tester because it must be generic
const testA = createTest(TestName.StringTestIsEmpty);
// Value param type must be string.
testA.test("myString");
// Example B
// condition param is number
const testB = createTest(TestName.StringLengthEquals, 2);
// Value param type must be string.
testB.test("myString");
// Example C
// condition param is string
const testC = createTest(TestName.StringEquals, "myString");
// Value param type must be string.
testC.test("myString");
// Example D
// condition param is number
const testD = createTest(TestName.NumberEquals, 10);
// Value param type must be number.
testD.test(5);