{"id":13465074,"url":"https://github.com/sindresorhus/typescript-definition-style-guide","last_synced_at":"2025-04-05T06:08:33.638Z","repository":{"id":41233356,"uuid":"145375843","full_name":"sindresorhus/typescript-definition-style-guide","owner":"sindresorhus","description":"Style guide for adding type definitions to my npm packages","archived":false,"fork":false,"pushed_at":"2022-11-06T13:57:38.000Z","size":23,"stargazers_count":570,"open_issues_count":0,"forks_count":11,"subscribers_count":14,"default_branch":"main","last_synced_at":"2025-03-28T21:24:44.934Z","etag":null,"topics":["style-guide","typescript","typescript-definitions"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc-by-4.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sindresorhus.png","metadata":{"funding":{"github":"sindresorhus","open_collective":"sindresorhus","custom":"https://sindresorhus.com/donate"},"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-08-20T06:32:00.000Z","updated_at":"2025-03-15T12:29:53.000Z","dependencies_parsed_at":"2022-09-06T04:40:40.356Z","dependency_job_id":null,"html_url":"https://github.com/sindresorhus/typescript-definition-style-guide","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sindresorhus%2Ftypescript-definition-style-guide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sindresorhus%2Ftypescript-definition-style-guide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sindresorhus%2Ftypescript-definition-style-guide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sindresorhus%2Ftypescript-definition-style-guide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sindresorhus","download_url":"https://codeload.github.com/sindresorhus/typescript-definition-style-guide/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247294539,"owners_count":20915340,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["style-guide","typescript","typescript-definitions"],"created_at":"2024-07-31T14:00:57.554Z","updated_at":"2025-04-05T06:08:33.621Z","avatar_url":"https://github.com/sindresorhus.png","language":null,"funding_links":["https://github.com/sponsors/sindresorhus","https://opencollective.com/sindresorhus","https://sindresorhus.com/donate"],"categories":["Others"],"sub_categories":[],"readme":"# TypeScript Definition Style Guide\n\n\u003e Style guide for adding type definitions to my npm packages\n\n*Open an issue if anything is unclear or if you have ideas for other checklist items.*\n\nThis style guide assumes your package is native ESM.\n\n## Checklist\n\n- Use tab-indentation and semicolons.\n- The definition should target the latest TypeScript version.\n- Exported properties/methods should be documented (see below).\n- The definition should be tested (see below).\n- When you have to use Node.js types, install the `@types/node` package as a dev dependency. **Do not** add a `/// \u003creference types=\"node\"/\u003e` triple-slash reference to the top of the definition file.\n- Third-party library types (everything in the `@types/*` namespace) must be installed as direct dependencies, if required. Use imports, not triple-slash references.\n- Ensure you're not falling for any of the [common mistakes](https://github.com/DefinitelyTyped/DefinitelyTyped/#common-mistakes).\n- For packages with a default export, use `export default function foo(…)` syntax.\n- Do not use `namespace`.\n- Use the name `\"types\"` and not `\"typings\"` for the TypeScript definition field in package.json.\n- Place `\"types\"` in package.json after all official package properties, but before custom properties, preferably after `\"dependencies\"` and/or `\"devDependencies\"`.\n- If the entry file in the package is named `index.js`, name the type definition file `index.d.ts` and put it in root.\\\n\tYou don't need to add a `types` field to package.json as TypeScript will infer it from the name.\n- Add the type definition file to the `files` field in package.json.\n- The pull request should have the title `Add TypeScript definition`. *(Copy-paste it so you don't get it wrong)*\n- **Help review [other pull requests](https://github.com/search?q=user%3Asindresorhus+is%3Apr+is%3Aopen+%22Add+TypeScript+definition%22\u0026type=Issues) that adds a type definition.**\n\nCheck out [this](https://github.com/sindresorhus/filled-array/commit/aae7539cb32f163cb063499664b012d0b04b3104), [this](https://github.com/sindresorhus/write-json-file/blob/main/index.d.ts), and [this](https://github.com/sindresorhus/delay/blob/main/index.d.ts) example for how it should be done.\n\n### Types\n\n- Types should not have namespaced names; `type Options {}`, not `type FooOptions {}`, unless there are multiple `Options` interfaces.\n- Use the array shorthand type notation; `number[]`, not `Array\u003cnumber\u003e`.\n- Use the `readonly number[]` notation; not `ReadonlyArray\u003cnumber\u003e`.\n- Prefer using the [`unknown` type](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-0.html#new-unknown-top-type) instead of `any` whenever possible.\n- Don't use abbreviation for type/variable/function names; `function foo(options: Options)`, not `function foo(opts: Opts)`.\n- When there are more than one [generic type variable](https://www.typescriptlang.org/docs/handbook/generics.html#working-with-generic-type-variables) in a method, they should have descriptive names; `type Mapper\u003cElement, NewElement\u003e = …`, not `type Mapper\u003cT, U\u003e = …`.\n- Don't prefix the name of interfaces with `I`; `Options`, not `IOptions`.\n- Imports, destructuring, and object literals should *not* have spaces around the identifier; `{foo}`, not `{ foo }`.\n- Don't use permissive types like `object` or `Function`. Use specific type-signatures like `Record\u003cstring, number\u003e` or `(input: string) =\u003e boolean;`.\n- Use `Record\u003cstring, any\u003e` for accepting objects with string index type and `Record\u003cstring, unknown\u003e` for returning such objects. The reason `any` is used for assignment is that TypeScript has special behavior for it:\n\t\u003e The index signature `Record\u003cstring, any\u003e` in TypeScript behaves specially: it’s a valid assignment target for any object type. This is a special rule, since types with index signatures don’t normally produce this behavior.\n\n#### Prefer read-only values\n\nMake something read-only when it's not meant to be modified. This is usually the case for return values and option interfaces. Get familiar with the `readonly` keyword for [properties](https://www.typescriptlang.org/docs/handbook/interfaces.html#readonly-properties) and [array/tuple types](https://github.com/Microsoft/TypeScript/wiki/What's-new-in-TypeScript#improvements-for-readonlyarray-and-readonly-tuples). There's also a [`Readonly` type](https://basarat.gitbooks.io/typescript/docs/types/readonly.html) to mark all properties as `readonly`.\n\nBefore:\n\n```ts\ntype Point = {\n\tx: number;\n\ty: number;\n\tchildren: Point[];\n};\n```\n\nAfter:\n\n```ts\ntype Point = {\n\treadonly x: number;\n\treadonly y: number;\n\treadonly children: readonly Point[];\n};\n```\n\n#### Import types explicitly\n\nDon't use implicit global types except for built-ins or when they can't be imported.\n\nBefore:\n\n```ts\nexport function getWindow(): Electron.BrowserWindow;\n```\n\nAfter:\n\n```ts\nimport {BrowserWindow} from 'electron';\n\nexport function getWindow(): BrowserWindow;\n```\n\n#### Readable named imports\n\nUse a readable name when using named imports.\n\nBefore:\n\n```ts\nimport {Writable} from 'node:stream';\n```\n\nAfter:\n\n```ts\nimport {Writable as WritableStream} from 'node:stream';\n```\n\n### Documentation\n\nExported definitions should be documented with [TSDoc](https://github.com/Microsoft/tsdoc). You can borrow text from the readme.\n\nExample:\n\n```ts\nexport type Options = {\n\t/**\n\tAllow negative numbers.\n\n\t@default true\n\t*/\n\treadonly allowNegative?: boolean;\n\n\t/**\n\tHas the ultimate foo.\n\n\tNote: Only use this for good.\n\n\t@default false\n\t*/\n\treadonly hasFoo?: boolean;\n\n\t/**\n\tWhere to save.\n\n\tDefault: [User's downloads directory](https://example.com)\n\n\t@example\n\t```\n\timport add from 'add';\n\n\tadd(1, 2, {saveDirectory: '/my/awesome/dir'})\n\t```\n\t*/\n\treadonly saveDirectory?: string;\n};\n\n/**\nAdd two numbers together.\n\n@param x - The first number to add.\n@param y - The second number to add.\n@returns The sum of `x` and `y`.\n*/\nexport default function add(x: number, y: number, options?: Options): number;\n```\n\nNote:\n\n- Don't prefix lines with `*`.\n- Don't [hard-wrap](https://stackoverflow.com/questions/319925/difference-between-hard-wrap-and-soft-wrap).\n- Put an empty line between type entries.\n- Sentences should start with an uppercase character and end in a dot.\n- There's an empty line after the function description.\n- Parameters and the return value should be documented.\n- There's a dash after the parameter name.\n- `@param` should not include the parameter type.\n- If the parameter description just repeats the parameter name, leave it out.\n- If the parameter is `options` it doesn't need a description.\n- If the function returns `void` or a wrapped `void` like `Promise\u003cvoid\u003e`, leave out `@returns`.\n- If you include an `@example`, there should be a newline above it. The example itself should be wrapped with triple backticks (```` ``` ````).\n- If the API accepts an options-object, define an `Options` type as seen above. Document default option values using the [`@default` tag](https://jsdoc.app/tags-default.html) (since type cannot have default values). If the default needs to be a description instead of a basic value, use the formatting `Default: Lorem Ipsum.`.\n- Use `@returns`, not `@return`.\n- Ambient declarations can't have default parameters, so in the case of a default method parameter, document it in the parameter docs instead, as seen in the above example.\n- `@returns` should not duplicate the type information unless it's impossible to describe it without.\n\t- `@returns A boolean of whether it was enabled.` → `@returns Whether it was enabled.`\n\n#### Code examples\n\n- Include as many code examples as possible. Borrow from the readme.\n- Code examples should be fully functional and should include the import statement.\n\n### Testing\n\nThe type definition should be tested with [`tsd`](https://github.com/SamVerschueren/tsd). [Example of how to integrate it.](https://github.com/sindresorhus/filled-array/commit/aae7539cb32f163cb063499664b012d0b04b3104)\n\nExample:\n\n```ts\nimport {expectType} from 'tsd';\nimport delay from './index.js';\n\nexpectType\u003cPromise\u003cvoid\u003e\u003e(delay(200));\n\nexpectType\u003cPromise\u003cstring\u003e\u003e(delay(200, {value: '🦄'}));\nexpectType\u003cPromise\u003cnumber\u003e\u003e(delay(200, {value: 0}));\n\nexpectType\u003cPromise\u003cnever\u003e\u003e(delay.reject(200, {value: '🦄'}));\nexpectType\u003cPromise\u003cnever\u003e\u003e(delay.reject(200, {value: 0}));\n```\n\nWhen it makes sense, also add a negative test using [`expectError()`](https://github.com/SamVerschueren/tsd#expecterrorfunction).\n\nNote:\n\n- The test file should be named `index.test-d.ts`.\n- `tsd` supports top-level `await`.\n- When testing promise-returning functions, don't use the `await` keyword. Instead, directly assert for a `Promise`, like in the example above. When you use `await`, your function can potentially return a bare value without being wrapped in a `Promise`, since `await` will happily accept non-`Promise` values, rendering your test meaningless.\n- Use [`const` assertions](https://github.com/Microsoft/TypeScript/wiki/What's-new-in-TypeScript#const-assertions) when you need to pass literal or readonly typed values to functions in your tests.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsindresorhus%2Ftypescript-definition-style-guide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsindresorhus%2Ftypescript-definition-style-guide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsindresorhus%2Ftypescript-definition-style-guide/lists"}