Skip to content

Commit

Permalink
Fix PackageJson and JsonObject types (#465)
Browse files Browse the repository at this point in the history
  • Loading branch information
skarab42 committed Sep 21, 2022
1 parent 2a2f310 commit f3b13e3
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 8 deletions.
2 changes: 1 addition & 1 deletion source/basic.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ This type can be useful to enforce some input to be JSON-compatible or as a supe
@category JSON
*/
export type JsonObject = {[Key in string]?: JsonValue};
export type JsonObject = {[Key in string]: JsonValue} & {[Key in string]?: JsonValue | undefined};

/**
Matches a JSON array.
Expand Down
8 changes: 5 additions & 3 deletions source/package-json.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type {LiteralUnion} from './literal-union';
import type {JsonObject, JsonValue} from './basic';

declare namespace PackageJson {
/**
Expand Down Expand Up @@ -27,7 +28,7 @@ declare namespace PackageJson {
};

export type DirectoryLocations = {
[directoryType: string]: unknown;
[directoryType: string]: JsonValue | undefined;

/**
Location for executable scripts. Sugar to generate entries in the `bin` property by walking the folder.
Expand Down Expand Up @@ -483,7 +484,7 @@ declare namespace PackageJson {
/**
Is used to set configuration parameters used in package scripts that persist across upgrades.
*/
config?: Record<string, unknown>;
config?: JsonObject;

/**
The dependencies of the package.
Expand Down Expand Up @@ -648,7 +649,7 @@ declare namespace PackageJson {
/**
Additional, less common properties from the [npm docs on `publishConfig`](https://docs.npmjs.com/cli/v7/configuring-npm/package-json#publishconfig).
*/
[additionalProperties: string]: unknown;
[additionalProperties: string]: JsonValue | undefined;

/**
When publishing scoped packages, the access level defaults to restricted. If you want your scoped package to be publicly viewable (and installable) set `--access=public`. The only valid values for access are public and restricted. Unscoped packages always have an access level of public.
Expand Down Expand Up @@ -677,6 +678,7 @@ Type for [npm's `package.json` file](https://docs.npmjs.com/creating-a-package-j
@category File
*/
export type PackageJson =
JsonObject &
PackageJson.NodeJsStandard &
PackageJson.PackageJsonStandard &
PackageJson.NonStandardEntryPoints &
Expand Down
34 changes: 30 additions & 4 deletions test-d/package-json.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {expectType, expectAssignable, expectNotAssignable} from 'tsd';
import type {PackageJson, LiteralUnion} from '../index';
import {expectType, expectAssignable, expectNotAssignable, expectError} from 'tsd';
import type {PackageJson, LiteralUnion, JsonObject} from '../index';

const packageJson: PackageJson = {};

Expand All @@ -26,7 +26,7 @@ expectType<{type: string; url: string; directory?: string} | string | undefined>
packageJson.repository,
);
expectType<PackageJson.Scripts | undefined>(packageJson.scripts);
expectType<Record<string, unknown> | undefined>(packageJson.config);
expectType<JsonObject | undefined>(packageJson.config);
expectType<PackageJson.Dependency | undefined>(packageJson.dependencies);
expectType<PackageJson.Dependency | undefined>(packageJson.devDependencies);
expectType<PackageJson.Dependency | undefined>(
Expand Down Expand Up @@ -81,4 +81,30 @@ expectAssignable<typeof packageJson['typesVersions']>({
'<4': undefined,
});

expectNotAssignable<Record<string, unknown>>(packageJson);
// Must reject an object that contains properties with `undefined` values.
// See https://github.com/sindresorhus/type-fest/issues/272
declare function setConfig(config: JsonObject): void;

expectError(setConfig({bugs: undefined}));
expectError(setConfig({bugs: {life: undefined}}));

expectNotAssignable<JsonObject>({bugs: undefined});
expectNotAssignable<JsonObject>({bugs: {life: undefined}});

expectAssignable<JsonObject>({});
expectAssignable<JsonObject>({bugs: 42});
expectAssignable<JsonObject>({bugs: [42]});
expectAssignable<JsonObject>({bugs: {life: 42}});

// `PackageJson` should be a valid `JsonObject`.
// See https://github.com/sindresorhus/type-fest/issues/79
type UnknownRecord = Record<string, unknown>;

const unknownRecord: UnknownRecord = {};
const jsonObject: JsonObject = {};

expectAssignable<UnknownRecord>(packageJson);
expectNotAssignable<PackageJson>(unknownRecord);

expectAssignable<PackageJson>(jsonObject);
expectAssignable<JsonObject>(packageJson);

0 comments on commit f3b13e3

Please sign in to comment.