我遵循TypeScript手册来实现用户定义的类型保护,但我仍然遇到错误,我无法弄清楚原因。我觉得它与我使用Object.keys有关,但我不太确定。
types.ts
type devices = 'Web' | 'iOS' | 'Android' | 'Gaming' | 'Mac' | 'PC';
type languages = 'Javascript' | 'PHP' | 'Ruby' | 'Python' | 'Java' | 'C#' | 'C++' | 'C' | 'Obj-C' | 'Swift';
type frameworks = 'React' | 'Angular' | 'Vue' | 'Ember' |
'Laravel' | 'Symfony' | 'CakePHP' | 'Yii' | 'Phalcon' |
'Rails' | 'Sinatra' | 'Padrino' | 'Hanami' | 'NYNY' | 'Django' | 'TurboGears' | 'web2py' | 'Pylons' |
'SpringMVC' | 'JSF' | 'GWT' | 'Spring Boot' | 'Grails'|
'ASP.NET' | 'Nancy';
type backends = 'Express' | 'Koa' | 'Mojito' | 'Meteor' | 'Sails';
export interface Proficiencies {
technology: devices | languages | frameworks | backends;
proficiency: 0 | 0.5 | 1 | 1.5 | 2 | 2.5 | 3 | 3.5 | 4 | 4.5 | 5;
}
export interface SurveyResponse {
[index: string]: string[] | Proficiencies[];
devices: devices[];
languages: languages[];
frameworks: frameworks[];
backends: backends[];
proficiencies: Proficiencies[];
}
main.ts
import { SurveyResponse, Proficiencies } from 'types.ts';
export const percentageMatch = (array1: string[], array2: string[]): number => {
const numberOfMatches: number = array1.reduce((accumulator, item) => {
if (array2.includes(item)) {
return accumulator + 1;
}
return accumulator;
}, 0);
return (numberOfMatches / array1.length) || 0;
};
export const proficienciesScore = (proficiencies1: Proficiencies[], proficiencies2: Proficiencies[]): number => {
return 1;
};
export const matchScore = (survey1: SurveyResponse, survey2: SurveyResponse): number => {
const categoryHighestScores: { [index: string]: number } = {
devices: 0.15,
languages: 0.15,
frameworks: 0.15,
backends: 0.15,
proficiencies: 0.40
};
const isProficienciesArray = (array: string[] | Proficiencies[]): array is Proficiencies[] => {
return (<Proficiencies[]>array)[0].technology !== undefined;
};
const categoryScores: number[] = Object.keys(survey1).map(category => {
if (isProficienciesArray(survey1[category])) {
return proficienciesScore(survey1[category], survey2[category]) * categoryHighestScores[category];
}
return percentageMatch(survey1[category], survey2[category]) * categoryHighestScores[category];
});
return categoryScores.reduce((accumulator, score): number => {
return accumulator + score;
}, 0);
};
我的categoryScores
常量中出现错误,特别是
Argument of type 'string[] | Proficiencies[]' is not assignable to parameter of type 'Proficiencies[]'.
Type 'string[]' is not assignable to type 'Proficiencies[]'.
Type 'string' is not assignable to type 'Proficiencies'.
和
Argument of type 'string[] | Proficiencies[]' is not assignable to parameter of type 'string[]'.
Type 'Proficiencies[]' is not assignable to type 'string[]'.
Type 'Proficiencies' is not assignable to type 'string'.
分别与survey1[category]
和proficienciesScore
函数调用的第一个参数percentageMatch
相关。我认为我已经正确实现了用户定义的类型保护(isProficienciesArray
),并且我想知道问题出在哪里。
答案 0 :(得分:1)
我能够通过
让它工作const categoryScores: number[] = Object.keys(survey1).map(category => {
const x = survey1[category];
const y = survey2[category];
if (isProficienciesArray(x) && isProficienciesArray(y)) {
return proficienciesScore(x, y) * categoryHighestScores[category];
}
else if (!isProficienciesArray(x) && !isProficienciesArray(y))
return percentageMatch(x, y) * categoryHighestScores[category];
});
答案 1 :(得分:1)
Aziz解决方案可以解决TypeScript编译器限制问题。
IMO,其他方法意味着更深入地修改代码。下一步可能是删除if (isProficienciesArray...)
/ else
语句(请参阅Object Calisthenics规则#2)。它将帮助TypeScript编译器进行类型推理,并在您喜欢这种代码时改进代码。
在下面的片段中,它使用字典/地图完成,如当前categoryHighestScores
变量,但封装了分数/匹配计算:
proficienciesScore
代表Proficiencies[]
,matchScore
用于其他string[]
数组。地图名为matchFnMap
。函数populateMatchFnMapWith()
有助于简化其创建。
// types.ts
// [...]
const emptySurveyResponse: SurveyResponse = {
devices: [],
languages: [],
frameworks: [],
backends: [],
proficiencies: []
};
export const surveyResponseCategories = Object.keys(emptySurveyResponse);
// main.ts
// [...]
interface MatchFn<T> {
(a: T, b: T): number;
}
const matchFnMap: {[category: string]: MatchFn<SurveyResponse>} = {};
function populateMatchFnMapWith(category: string, categoryHighestScore: number, match: MatchFn<string[]|Proficiencies[]>) {
matchFnMap[category] =
(survey1: SurveyResponse, survey2: SurveyResponse) =>
categoryHighestScore *
match(survey1[category],
survey2[category]);
}
populateMatchFnMapWith('devices', 0.15, percentageMatch);
populateMatchFnMapWith('languages', 0.15, percentageMatch);
populateMatchFnMapWith('frameworks', 0.15, percentageMatch);
populateMatchFnMapWith('backends', 0.15, percentageMatch);
populateMatchFnMapWith('proficiencies', 0.40, proficienciesScore);
const matchScore = (survey1: SurveyResponse, survey2: SurveyResponse) =>
surveyResponseCategories.reduce((total, category) => {
const computeScore = matchFnMap[category];
return total + computeScore(survey1, survey2);
}, 0);
它仍处于功能编程风格。进一步的步骤意味着将模型修改为更多OOP样式以收集数据和计算。