Skip to content

Instantly share code, notes, and snippets.

@jmakeig
Last active January 6, 2023 06:30
Show Gist options
  • Save jmakeig/8b2bdd311dbb03f58cddc66866457990 to your computer and use it in GitHub Desktop.
Save jmakeig/8b2bdd311dbb03f58cddc66866457990 to your computer and use it in GitHub Desktop.
JSDoc can’t describe some generic functions declared in Typescript
/** @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));
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