Предположим, у меня есть схема в javascript:
import {z} from "zod";
let personSchema = z.object({
name: z.string(),
id: z.number()
});
теперь я хочу использовать этот тип где-то еще:
/**
* @param {{name:string, id:number}} person
* but should instead be something like this?:
* @param {???(typeof z)["infer"]<typeof personSchema>???} person
*/
function (person) {
person.name; // autocompletions and vscode linting should work here
// do stuff
}
Конечно, это было бы легко в машинописи, но я пытаюсь использовать JSDOC, так как проект не позволяет использовать TypeScript.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Это работает:
/**
* @param {ReturnType<(typeof personSchema)["parse"]>} person
*/
function (person) {
person.name; // autocompletions and vscode linting should work here
// do stuff
}
Хотя это работает, я подозреваю, что есть лучшее решение.
Одна вещь, которую вы можете попробовать, — это воспользоваться преимуществом разделения между пространством имен типа и пространством имен значений, экспортируя тип схемы с тем же именем, что и схема. Например, вы могли бы сказать
export const personSchema = z.object({ /* ... */ });
// If you're using eslint, it may complain here but you can ignore
// the redeclaration complaint
export type personSchema = z.infer<typeof personSchema>;
Когда Typescript обрабатывает типы из JSDOC, тип personSchema будет импортирован и разрешен, поэтому вы получите правильное значение с помощью:
/**
* @param {personSchema} person
*/
function (person) {
person.name;
};
Это будет работать с обычным JS, поскольку типы не будут существовать, поэтому будет импортирована только схема, и это также будет работать с TS, поскольку он может различать что-то, используемое как тип, и что-то, что является значением.
Разве z.infer<typeof personSchema> не требует шага компиляции машинописного текста?
Верно. Думаю, я не был уверен, какова точная настройка ОП. Я думал, что он импортирует свою схему из кода TypeScript в JavaScript, но я думаю, что ваша интерпретация, вероятно, верна, и я все равно предпочел бы ваш ответ, поскольку он позволяет избежать перегрузки имени и дает лучшее имя для типа.
Вот способ использования z.infer для определения типа с помощью jsdoc (аналогично тому, как вы делаете это в Typescript), а затем используйте новый тип в аннотации функции:
import {z} from "zod";
/**
* @typedef {z.infer<typeof PersonSchema>} Person
*/
let PersonSchema = z.object({
name: z.string(),
id: z.number()
});
/**
* @param {Person} person
*/
function (person) {
person.name; // autocompletions and vscode linting should work here
// do stuff
}
интересно, что z.infer идет в комплекте из импорта. Спасибо!
Следуя вашей подсказке, вы также можете определить тип Person после схемы:
@typedef {ReturnType<(typeof personSchema)["parse"]>} Person... затем использовать@param {Person} personв аннотации jsdoc функции.