Не смотря на то, что с TypeScript я познакомился еще до появления на свет Visual Studio Code, мне еще ни разу не довелось использовать его в повседневной работе. Пишу на ES6 (Node.js), стараюсь документировать код с помощью jsdoc, но зачастую одних только комментов не хватает для того, чтобы intellisense подсказал мне с чем я имею дело в текущий момент времени, а иногда очень хотелось бы (и не мне одному), поэтому я решил попробовать миксовать declaration files с "vanilla JS".
Сначала покажу что же получилось в итоге.
Модуль:
- node_modules/incrementer/index.js:
Приложение:
- app.js:
Подсказки:
"Ну после такого дождя жди хороший отёл" :).
А теперь по порядку. Семь подходов.
Подход #1. Ничего кроме кода.
Модуль:
- inc.js:
Приложение:
- app.js:
Подсказки:
Intellisense "знает" имена параметров экспортируемой модулем функции, не более того.
Подход #2. Добавим комменты jsdoc.
Модуль:
- inc.js:
Приложение: без изменений.
Подсказки:
Уже кое-что: появились типы параметров.
Подход #3. Попробуем закомментировать подробнее.
Модуль:
- inc.js:
Приложение: без изменений.
Подсказки:
В настоящее время большая часть моего кода выглядит примерно так. И это максимум из того, что я могу выжать из jsdoc. Предложения принимаются.
Подход #4. Создадим файл объявления нашего модуля.
Модуль:
- inc.js:
Файл объявления:
- typings/inc.d.ts:
Приложение: без изменений.
Подсказки:
И это все что мне нужно от intellisense!
Подход #5. Используем классы.
Модуль: без изменений.
Файл объявления:
- typings/inc.d.ts:
Можно было без префикса declare, но хуже не будет.
Приложение: без изменений.
Подсказки:
Тоже неплохо, наверное даже более... "честно" что ли, ведь на самом деле под капотом модуля живет конструктор, хотя и предыдущий вариант меня вполне устроил.
Подход #6. Создаем модуль в каталоге node_modules.
Модуль:
- node_modules/incr.js:
Файл объявления:
- typings/incr.d.ts:
Приложение:
- app.js:
Подсказки:
Подход #7. Создаем еще один модуль в каталоге node_modules, включаем файл объявления в комплект поставки модуля.
Модуль:
- node_modules/incrementer/index.js:
- package.json:
Обращаю внимание на поле "types": "index.d.ts" - значение по умолчанию, поэтому в нашем случае наличие этого поля не обязательно.
Файл объявления:
- node_modules/incrementer/index.d.js:
Приложение:
- app.js:
Подсказки:
Вот и все, остается найти время написать файлы объявления к созданному ранее JavaScript коду, и "хороший отёл" не заставит себя долго ждать :).
Сначала покажу что же получилось в итоге.
Модуль:
- node_modules/incrementer/index.js:
const Inc = function (value, { prefix }) { this._value = value; this._prefix = prefix; }; const inc = function (value, separator = ': ') { return `${this._prefix}${separator}${value + this._value}`; }; Inc.prototype = { inc }; module.exports = (value, opts) => new Inc(value, opts);
Приложение:
- app.js:
const Inc = require('incrementer'); const inc = Inc(1, { prefix: 'result' }); const result = inc.inc(2); console.log(result);
Подсказки:
"Ну после такого дождя жди хороший отёл" :).
А теперь по порядку. Семь подходов.
Подход #1. Ничего кроме кода.
Модуль:
- inc.js:
const Inc = function (value, { prefix }) { this._value = value; this._prefix = prefix; }; const inc = function (value, separator = ': ') { return `${this._prefix}${separator}${value + this._value}`; }; Inc.prototype = { inc }; module.exports = (value, opts) => new Inc(value, opts);
Приложение:
- app.js:
const Inc = require('./inc'); const inc = Inc(1, { prefix: 'result' }); const result = inc.inc(2); console.log(result);
Подсказки:
Intellisense "знает" имена параметров экспортируемой модулем функции, не более того.
Подход #2. Добавим комменты jsdoc.
Модуль:
- inc.js:
/** * @constructor * @param {number} value * @param {Object} opts * @param {string} opts.prefix */ const Inc = function (value, { prefix }) { this._value = value; this._prefix = prefix; }; /** * @param {number} value * @param {string} [separator=': '] * @returns {string} */ const inc = function (value, separator = ': ') { return `${this._prefix}${separator}${value + this._value}`; }; Inc.prototype = { inc }; /** * @param {number} value * @param {Object} opts * @param {string} opts.prefix */ module.exports = (value, opts) => new Inc(value, opts);
Приложение: без изменений.
Подсказки:
Уже кое-что: появились типы параметров.
Подход #3. Попробуем закомментировать подробнее.
Модуль:
- inc.js:
/** * @constructor * @param {number} value * @param {opts} opts */ const Inc = function (value, { prefix }) { this._value = value; this._prefix = prefix; }; /** * @typedef {function} inc * @param {number} value * @param {string} [separator=': '] * @returns {string} */ const inc = function (value, separator = ': ') { return `${this._prefix}${separator}${value + this._value}`; }; Inc.prototype = { inc }; /** * @typedef {Object} incrementer * @property {inc} inc */ /** * @typedef {Object} opts * @property {string} prefix */ /** * @param {number} value * @param {opts} opts * @returns {incrementer} */ module.exports = (value, opts) => new Inc(value, opts);
Приложение: без изменений.
Подсказки:
В настоящее время большая часть моего кода выглядит примерно так. И это максимум из того, что я могу выжать из jsdoc. Предложения принимаются.
Подход #4. Создадим файл объявления нашего модуля.
Модуль:
- inc.js:
const Inc = function (value, { prefix }) { this._value = value; this._prefix = prefix; }; const inc = function (value, separator = ': ') { return `${this._prefix}${separator}${value + this._value}`; }; Inc.prototype = { inc }; /** @type {Inc} */ module.exports = (value, opts) => new Inc(value, opts);
Файл объявления:
- typings/inc.d.ts:
interface Inc { /** * Returns incrementer */ (value: number, opts: { prefix: string }): incrementer; } interface incrementer { /** * Increments number, returns string representation */ inc(value: number, separator = ': '): string; }
Подсказки:
И это все что мне нужно от intellisense!
Подход #5. Используем классы.
Модуль: без изменений.
Файл объявления:
- typings/inc.d.ts:
declare interface Inc { /** * Returns incrementer */ (value: number, opts: { prefix: string }): CInc; } declare class CInc { inc: inc; constructor(value: number, opts: { prefix: string }); } declare interface inc { /** * Increments number, returns string representation */ (value: number, separator = ': '): string; }
Приложение: без изменений.
Подсказки:
Тоже неплохо, наверное даже более... "честно" что ли, ведь на самом деле под капотом модуля живет конструктор, хотя и предыдущий вариант меня вполне устроил.
Подход #6. Создаем модуль в каталоге node_modules.
Модуль:
- node_modules/incr.js:
const Inc = function (value, { prefix }) { this._value = value; this._prefix = prefix; }; const inc = function (value, separator = ': ') { return `${this._prefix}${separator}${value + this._value}`; }; Inc.prototype = { inc }; module.exports = (value, opts) => new Inc(value, opts);
Файл объявления:
- typings/incr.d.ts:
declare module "incr" { /** * Returns incrementer */ function Incr (value: number, opts: { prefix: string }): CIncr class CIncr { inc: incr; constructor(value: number, opts: { prefix: string }); } interface incr { /** * Increments number, returns string representation */ (value: number, separator = ': '): string; } export = Incr }
Приложение:
- app.js:
const Inc = require('incr'); const inc = Inc(1, { prefix: 'result' }); const result = inc.inc(2); console.log(result);
Подсказки:
Подход #7. Создаем еще один модуль в каталоге node_modules, включаем файл объявления в комплект поставки модуля.
Модуль:
- node_modules/incrementer/index.js:
const Inc = function (value, { prefix }) { this._value = value; this._prefix = prefix; }; const inc = function (value, separator = ': ') { return `${this._prefix}${separator}${value + this._value}`; }; Inc.prototype = { inc }; module.exports = (value, opts) => new Inc(value, opts);
- package.json:
{ "name": "incrementer", "version": "1.0.0", "description": "", "main": "index.js", "types": "index.d.ts", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "private": true }
Обращаю внимание на поле "types": "index.d.ts" - значение по умолчанию, поэтому в нашем случае наличие этого поля не обязательно.
Файл объявления:
- node_modules/incrementer/index.d.js:
declare module "incrementer" { /** * Returns incrementer */ function Incrementer (value: number, opts: { prefix: string }): CIncrementer class CIncrementer { inc: increment; constructor(value: number, opts: { prefix: string }); } interface increment { /** * Increments number, returns string representation */ (value: number, separator = ': '): string; } export = Incrementer }
Приложение:
- app.js:
const Inc = require('incrementer'); const inc = Inc(1, { prefix: 'result' }); const result = inc.inc(2); console.log(result);
Подсказки:
Вот и все, остается найти время написать файлы объявления к созданному ранее JavaScript коду, и "хороший отёл" не заставит себя долго ждать :).
Комментариев нет:
Отправить комментарий
Комментарий будет опубликован после модерации