Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions examples/required-options/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# required options Example

`Base` has no required options by default, so the following code has no type errors.

```js
import { Base } from "javascript-plugin-architecture-with-typescript-definitions";

const base1 = new Base();
const base2 = new Base({});
```

But required options can be added by extending the `Base.Optiions` interface.

```ts
declare module "javascript-plugin-architecture-with-typescript-definitions" {
namespace Base {
interface Options {
myRequiredUserOption: string;
}
}
}
```

With that extension, the same code will have type a type error

```ts
// TS Error: Property 'myRequiredUserOption' is missing in type '{}' but required in type 'Options'
const base = new Base({});
```
12 changes: 12 additions & 0 deletions examples/required-options/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Base } from "../../index.js";
export { Base } from "../../index.js";

declare module "../.." {
namespace Base {
interface Options {
myRequiredUserOption: string;
}
}
}

export class MyBase extends Base {}
13 changes: 13 additions & 0 deletions examples/required-options/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Base } from "../../index.js";

/**
* @param {Base} base
* @param {Base.Options} options
*/
function pluginRequiringOption(base, options) {
if (!options.myRequiredUserOption) {
throw new Error('Required option "myRequiredUserOption" missing');
}
}

export const MyBase = Base.plugin(pluginRequiringOption);
11 changes: 11 additions & 0 deletions examples/required-options/index.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { MyBase } from "./index.js";

// @ts-expect-error - An argument for 'options' was not provided
new MyBase();

// @ts-expect-error - Type '{}' is missing the following properties from type 'Options': myRequiredUserOption
new MyBase({});

new MyBase({
myRequiredUserOption: "",
});
18 changes: 18 additions & 0 deletions examples/required-options/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { test } from "uvu";
import * as assert from "uvu/assert";

import { MyBase } from "./index.js";

test("new MyBase()", () => {
assert.throws(() => new MyBase());
});

test("new MyBase({})", () => {
assert.throws(() => new MyBase({}));
});

test('new MyBase({ myRequiredUserOption: ""})', () => {
assert.not.throws(() => new MyBase({ myRequiredUserOption: "" }));
});

test.run();
48 changes: 24 additions & 24 deletions index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ const BaseWithEmptyDefaults = Base.defaults({

// 'version' is missing and should still be required
// @ts-expect-error
new BaseWithEmptyDefaults()
new BaseWithEmptyDefaults();

// 'version' is missing and should still be required
// @ts-expect-error
new BaseWithEmptyDefaults({})
new BaseWithEmptyDefaults({});

const BaseLevelOne = Base.plugin(fooPlugin).defaults({
defaultOne: "value",
Expand All @@ -35,8 +35,8 @@ new BaseLevelOne();
new BaseLevelOne({});

expectType<{
defaultOne: string,
version: string,
defaultOne: string;
version: string;
}>(BaseLevelOne.defaultOptions);

const baseLevelOne = new BaseLevelOne({
Expand All @@ -54,9 +54,9 @@ const BaseLevelTwo = BaseLevelOne.defaults({
});

expectType<{
defaultOne: string,
defaultTwo: number,
version: string,
defaultOne: string;
defaultTwo: number;
version: string;
}>({ ...BaseLevelTwo.defaultOptions });

// Because 'version' is already provided, this needs no argument
Expand All @@ -65,11 +65,11 @@ new BaseLevelTwo({});

// 'version' may be overriden, though it's not necessary
new BaseLevelTwo({
version: 'new version',
version: "new version",
});

const baseLevelTwo = new BaseLevelTwo({
optionTwo: true
optionTwo: true,
});

expectType<number>(baseLevelTwo.options.defaultTwo);
Expand All @@ -80,14 +80,14 @@ expectType<string>(baseLevelTwo.options.version);
baseLevelTwo.unknown;

const BaseLevelThree = BaseLevelTwo.defaults({
defaultThree: ['a', 'b', 'c'],
defaultThree: ["a", "b", "c"],
});

expectType<{
defaultOne: string,
defaultTwo: number,
defaultThree: string[],
version: string,
defaultOne: string;
defaultTwo: number;
defaultThree: string[];
version: string;
}>({ ...BaseLevelThree.defaultOptions });

// Because 'version' is already provided, this needs no argument
Expand All @@ -96,13 +96,13 @@ new BaseLevelThree({});

// Previous settings may be overriden, though it's not necessary
new BaseLevelThree({
optionOne: '',
optionOne: "",
optionTwo: false,
version: 'new version',
version: "new version",
});

const baseLevelThree = new BaseLevelThree({
optionThree: [0, 1, 2]
optionThree: [0, 1, 2],
});

expectType<string>(baseLevelThree.options.defaultOne);
Expand Down Expand Up @@ -185,19 +185,19 @@ expectType<{
// @ts-expect-error - .options from .defaults() is only supported until a depth of 4
}>({ ...baseLevelFour.options });

const BaseWithChainedDefaultsAndPlugins = Base
.defaults({
defaultOne: "value",
})
const BaseWithChainedDefaultsAndPlugins = Base.defaults({
defaultOne: "value",
})
.plugin(fooPlugin)
.defaults({
defaultTwo: 0,
});

const baseWithChainedDefaultsAndPlugins =
new BaseWithChainedDefaultsAndPlugins({
const baseWithChainedDefaultsAndPlugins = new BaseWithChainedDefaultsAndPlugins(
{
version: "1.2.3",
});
}
);

expectType<string>(baseWithChainedDefaultsAndPlugins.foo);

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
"types": "./index.d.ts",
"scripts": {
"test": "npm run -s test:code && npm run -s test:typescript && npm run -s test:coverage",
"test:code": "c8 node test.js",
"test:code": "c8 uvu . '^(examples/.*/)?test.js$'",
"test:coverage": "c8 check-coverage",
"test:typescript": "tsd"
"test:typescript": "tsd && tsd examples/*"
},
"repository": "github:gr2m/javascript-plugin-architecture-with-typescript-definitions",
"keywords": [
Expand Down