Last active
January 6, 2023 06:30
-
-
Save jmakeig/8b2bdd311dbb03f58cddc66866457990 to your computer and use it in GitHub Desktop.
JSDoc can’t describe some generic functions declared in Typescript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** @typedef {{name: string; title: string; description: string; sets: any[]; }} Workout */ | |
/** @typedef {{name: string; instructions: string;}} Exercise */ | |
/** @typedef {"en" | "fr" | "de" | "jp" | "zh" | "he"} Lang */ | |
/** @typedef {string | {[L in Lang]?: string}} Message */ | |
/** @typedef {{for: string, message?: Message}} ValidationResult */ | |
/** | |
* @template Entity | |
* @typedef {{(condition: {(entity: Entity): boolean}, id: string, message: Message): {(entity: Entity): ValidationResult[]}}} RuleCreator<Entity> | |
*/ | |
/** | |
* @template Entity | |
* @type {RuleCreator<any>} // <= Ahh! Why can’t I use the generic Entity here? https://github.com/microsoft/TypeScript/issues/27387#issuecomment-659671940 | |
*/ | |
function create_rule(condition, id, message) { | |
return function(entity) { | |
if(condition(entity)) { | |
return [{ | |
for: id, | |
message | |
}] | |
} | |
return []; | |
} | |
} | |
/** | |
* | |
* @param {Workout} workout | |
* @returns {ValidationResult[]} | |
*/ | |
function validate_workout(workout) { | |
/** @type {{(entity: Workout): ValidationResult[]}[]} */ | |
const rules = [ | |
create_rule(w => !w.title.match(/[\p{L}\p{N}]+/gu), 'title', {en: 'Title must contain characters'}), | |
create_rule(w => !w.title.startsWith('asdf'), 'title', {en: 'Title must start with asdf'}) | |
]; | |
return rules.flatMap(rule => rule(workout)) | |
} | |
/** | |
* | |
* @param {Exercise} exercise | |
* @returns {ValidationResult[]} | |
*/ | |
function validate_exercise(exercise) { | |
/** @type {{(entity: Exercise): ValidationResult[]}[]} */ | |
const rules = [ | |
create_rule(ex => ex.instructions === 'inst', 'instructions', 'nope') | |
]; | |
return rules.flatMap(rule => rule(exercise)) | |
} | |
/** @type {Workout} */ | |
const tmp = { name: 'a', title: '!!!!!!!!', description: '', sets: []}; | |
console.log(validate_workout(tmp)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type Workout = { | |
name: string; | |
title: string; | |
description: string; | |
sets: any[]; | |
}; | |
type Exercise = { | |
name: string; | |
instructions: string; | |
}; | |
type Lang = "en" | "fr" | "de" | "jp" | "zh" | "he"; | |
type Message = string | { | |
en?: string; | |
fr?: string; | |
de?: string; | |
jp?: string; | |
zh?: string; | |
he?: string; | |
}; | |
type ValidationResult = { | |
for: string; | |
message?: Message; | |
}; | |
//type RuleCreator<Entity> = (condition: (entity: Entity) => boolean, id: string, message: Message) => (entity: Entity) => ValidationResult[]; | |
function create_rule<Entity>(condition: (entity: Entity) => boolean, id: string, message: Message) { | |
return function(entity: Entity) { | |
if(condition(entity)) { | |
return [{ | |
for: id, | |
message | |
}] | |
} | |
return []; | |
} | |
} | |
function validate_workout(workout: Workout): ValidationResult[] { | |
const rules = [ | |
create_rule<Workout>(w => !w.title.match(/[\p{L}\p{N}]+/gu), 'title', {en: 'Title must contain characters'}), | |
create_rule<Workout>(w => !w.title.startsWith('asdf'), 'title', {en: 'Title must start with asdf'}) | |
]; | |
//return rules.reduce((results, rule) => [...results, ...rule(workout)], []); | |
return rules.flatMap(rule => rule(workout)) | |
} | |
function validate_exercise(exercise: Exercise): ValidationResult[] { | |
const rules = [ | |
create_rule<Exercise>(e => e.instructions !== 'inst', 'instructions', {zh: '错误'}), | |
]; | |
return rules.flatMap(rule => rule(exercise)) | |
} | |
const tmp: Workout = { name: 'a', title: '!!!!!!!!', description: '', sets: []}; | |
console.log(validate_workout(tmp)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment