Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance Except type #560

Merged
merged 28 commits into from Mar 23, 2023
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
5b3138b
add StrictExcept type
orimiles5 Feb 26, 2023
fd7733a
prettier
orimiles5 Feb 26, 2023
29ce64d
added example for StrictExcept
orimiles5 Feb 26, 2023
03efc42
create Except type with optional strict
orimiles5 Feb 28, 2023
a0636bb
change name to
orimiles5 Feb 28, 2023
8bcc45c
change to single quotes
orimiles5 Feb 28, 2023
3c5e005
make StrictExcept false by default
orimiles5 Mar 1, 2023
0b5573b
remove test for strict-except
orimiles5 Mar 1, 2023
3ef2af0
Update except.d.ts
sindresorhus Mar 10, 2023
f14a038
Update except.d.ts
sindresorhus Mar 10, 2023
d7a1d0f
Add `IsLiteral` types (#563)
tommy-mitchell Mar 10, 2023
dfb46ad
Add `AbstractClass` type (#559)
rayrw Mar 11, 2023
7aac550
fix import statment and remove extra types
orimiles5 Mar 11, 2023
3b30962
set tsd to ignore noUnusedLocals error by default
orimiles5 Mar 11, 2023
911352c
add test cases for strict except
orimiles5 Mar 11, 2023
3432e46
Merge branch 'sindresorhus:main' into dev
orimiles5 Mar 11, 2023
5de63de
Update except.d.ts
sindresorhus Mar 14, 2023
e2a2cc0
Merge branch 'main' into dev
sindresorhus Mar 14, 2023
9d63b07
change strict option name to be more specific and document the trade-off
orimiles5 Mar 14, 2023
730d469
Fix documentation
orimiles5 Mar 14, 2023
6ffbed6
Update Except type documentation
orimiles5 Mar 14, 2023
880e7e4
Merge branch 'main' into 'dev'
orimiles5 Mar 22, 2023
87fcc50
Modify Except type docs
orimiles5 Mar 22, 2023
af2e28b
Modify ExceptOptions docs
orimiles5 Mar 22, 2023
f8e36b3
Update readme.md
sindresorhus Mar 23, 2023
f5d2a10
Update except.d.ts
sindresorhus Mar 23, 2023
0a15a94
Update except.d.ts
sindresorhus Mar 23, 2023
fa7c464
Merge branch 'main' into dev
sindresorhus Mar 23, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion readme.md
Expand Up @@ -902,4 +902,4 @@ You can find some examples in the [TypeScript docs](https://www.typescriptlang.o

## License

SPDX-License-Identifier: (MIT OR CC0-1.0)
SPDX-License-Identifier: (MIT OR CC0-1.0)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't make unrelated changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't figure out what was the change, maybe it's a white space?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the trailing new line was changed.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@orimiles5 This still needs to be fixed.

Copy link
Contributor Author

@orimiles5 orimiles5 Mar 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sindresorhus Could you give me some advice on how to fix this?

76 changes: 67 additions & 9 deletions source/except.d.ts
Expand Up @@ -25,9 +25,18 @@ type Filtered = Filter<'bar', 'foo'>;
//=> 'bar'
```

@see {Except}
@see {NonStrictExcept}
*/
type Filter<KeyType, ExcludeType> = IsEqual<KeyType, ExcludeType> extends true ? never : (KeyType extends ExcludeType ? never : KeyType);
type Filter<KeyType, ExcludeType> =
IsEqual<KeyType, ExcludeType> extends true ? never :
KeyType extends ExcludeType ? never : KeyType;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated change.

Suggested change
@see {NonStrictExcept}
*/
type Filter<KeyType, ExcludeType> = IsEqual<KeyType, ExcludeType> extends true ? never : (KeyType extends ExcludeType ? never : KeyType);
type Filter<KeyType, ExcludeType> =
IsEqual<KeyType, ExcludeType> extends true ? never :
KeyType extends ExcludeType ? never : KeyType;
@see {Except}
*/
type Filter<KeyType, ExcludeType> = IsEqual<KeyType, ExcludeType> extends true ? never : (KeyType extends ExcludeType ? never : KeyType);


type ExceptOptions = {
/**
@default false
*/
strict?: boolean;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could add a description to the option:

Suggested change
type ExceptOptions = {
/**
@default false
*/
strict?: boolean;
};
type ExceptOptions = {
/**
Disallow assigning non-specified properties.
Setting this to `false` is not recommended. Included for backwards-compatability.
@default false
*/
strict?: boolean;
};


/**
Create a type from an object type without certain keys.
Expand All @@ -36,22 +45,71 @@ This type is a stricter version of [`Omit`](https://www.typescriptlang.org/docs/

This type was proposed to the TypeScript team, which declined it, saying they prefer that libraries implement stricter versions of the built-in types ([microsoft/TypeScript#30825](https://github.com/microsoft/TypeScript/issues/30825#issuecomment-523668235)).

The NonStrictExcept refers to the standard Except method that permits the assignment of an object with additional properties to an object of a different type.
@see https://github.com/sindresorhus/type-fest/issues/556

@category Object
*/
type NonStrictExcept<ObjectType, KeysType extends keyof ObjectType> = {
[KeyType in keyof ObjectType as Filter<KeyType, KeysType>]: ObjectType[KeyType];
};

/**
Create a type from an object type without certain keys - in stricter way.
When the "strict" option in ExceptOptions is true, StrictExcept will be used.

The StrictExcept method resolves the problem that arises when an object with additional properties is assigned to an object of a different type.
@see https://github.com/sindresorhus/type-fest/issues/556

@category Object
*/

type StrictExcept<ObjectType, KeysType extends keyof ObjectType> = NonStrictExcept<ObjectType, KeysType> & Partial<Record<KeysType, never>>;

/**
The Except type is the exported type, which determines the appropriate method to use (NonStrictExcept or StrictExcept) based on the options provided as the third argument (which is set to false by default).

@example
```
import type {Except} from 'type-fest';
import {Except} from 'type-fest';
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't make unrelated changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.


type Foo = {
a: number;
b: string;
c: boolean;
};

type FooWithoutA = Except<Foo, 'a' | 'c'>;
//=> {b: string};
type FooWithoutA = Except<Foo, 'a', {strict: false}>; // False by default

const foo: Foo = {
a: 1,
b: 'b',
c: true,
};

const fooWithoutA: FooWithoutA = foo; // No error
//=> NonStrictExcept<Foo, 'a'>;

@example
```
import {Except} from 'type-fest';

@category Object
*/
export type Except<ObjectType, KeysType extends keyof ObjectType> = {
[KeyType in keyof ObjectType as Filter<KeyType, KeysType>]: ObjectType[KeyType];
type Foo = {
a: number;
b: string;
c: boolean;
};

type FooWithoutA = Except<Foo, 'a', {strict: true}>;

const foo: Foo = {
a: 1,
b: 'b',
c: true,
};

const fooWithoutA: FooWithoutA = foo; // Error
//=> StrictExcept<Foo, 'a'>;
*/
export type Except<ObjectType, KeysType extends keyof ObjectType, Options extends ExceptOptions = {strict: false}> =
Options['strict'] extends false ? NonStrictExcept<ObjectType, KeysType> : StrictExcept<ObjectType, KeysType>;
2 changes: 1 addition & 1 deletion test-d/except.ts
Expand Up @@ -11,7 +11,7 @@ type Example = {
bar: string;
sindresorhus marked this conversation as resolved.
Show resolved Hide resolved
};

const test: Except<Example, 'bar'> = {foo: 123, bar: 'asdf'};
const test: Except<Example, 'bar', {strict: false}> = {foo: 123, bar: 'asdf'};
expectType<number>(test.foo);
// eslint-disable-next-line @typescript-eslint/dot-notation
expectType<unknown>(test['bar']);