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

Internal aliasing #90

Merged
merged 5 commits into from
Mar 12, 2019
Merged
Show file tree
Hide file tree
Changes from all 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
18 changes: 2 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ npm install --save-dev simplytyped

**[Objects](#objects)**

[AllKeys](#allkeys) - [AllRequired](#allrequired) - [CombineObjects](#combineobjects) - [DeepPartial](#deeppartial) - [DeepReadonly](#deepreadonly) - [DiffKeys](#diffkeys) - [GetKey](#getkey) - [HasKey](#haskey) - [Intersect](#intersect) - [Keys](#keys) - [KeysByType](#keysbytype) - [Merge](#merge) - [ObjectKeys](#objectkeys) - [ObjectType](#objecttype) - [Omit](#omit) - [Optional](#optional) - [Overwrite](#overwrite) - [PlainObject](#plainobject) - [PureKeys](#purekeys) - [Required](#required) - [SharedKeys](#sharedkeys) - [StrictUnion](#strictunion) - [StringKeys](#stringkeys) - [TaggedObject](#taggedobject) - [UnionizeProperties](#unionizeproperties) - [UnionKeys](#unionkeys)
[AllKeys](#allkeys) - [AllRequired](#allrequired) - [CombineObjects](#combineobjects) - [DeepPartial](#deeppartial) - [DeepReadonly](#deepreadonly) - [DiffKeys](#diffkeys) - [GetKey](#getkey) - [HasKey](#haskey) - [Intersect](#intersect) - [KeysByType](#keysbytype) - [Merge](#merge) - [ObjectKeys](#objectkeys) - [ObjectType](#objecttype) - [Omit](#omit) - [Optional](#optional) - [Overwrite](#overwrite) - [PlainObject](#plainobject) - [PureKeys](#purekeys) - [Required](#required) - [SharedKeys](#sharedkeys) - [StrictUnion](#strictunion) - [StringKeys](#stringkeys) - [TaggedObject](#taggedobject) - [UnionizeProperties](#unionizeproperties) - [UnionKeys](#unionkeys)

**[Utils](#utils)**

Expand Down Expand Up @@ -221,7 +221,7 @@ test('Can make an object with functions readonly', t => {

### DiffKeys
Gets all of the keys that are different between two objects.
This is a set difference between `Keys<T>` and `Keys<U>`.
This is a set difference between `keyof T` and `keyof U`.
Note that calling this with arguments reversed will have different results.
```ts
test('Can get all keys that are different between objects', t => {
Expand Down Expand Up @@ -283,20 +283,6 @@ test('Can get an object with only shared properties', t => {

```

### Keys
No different than `keyof`, but can look a bit nicer when nesting many types deep.
```ts
test('Can get keys from object', t => {
type obj = { x: number, y: string, z: boolean };
type expected = 'x' | 'y' | 'z';
type got = Keys<obj>;

assert<got, expected>(t);
assert<expected, got>(t);
});

```

### KeysByType
Gets all keys that point to a given type.
```ts
Expand Down
8 changes: 4 additions & 4 deletions src/impl/objects.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { DeepReadonly, Keys, TaggedObject, ObjectKeys } from '../types/objects';
import { DeepReadonly, TaggedObject } from '../types/objects';

/**
* Type guard for any key, `k`.
* Marks `k` as a key of `T` if `k` is in `obj`.
* @param obj object to query for key `k`
* @param k key to check existence in `obj`
*/
export function isKeyOf<T extends object>(obj: T, k: ObjectKeys): k is keyof T {
export function isKeyOf<T extends object>(obj: T, k: keyof any): k is keyof T {
return k in obj;
}

Expand All @@ -17,7 +17,7 @@ export function isKeyOf<T extends object>(obj: T, k: ObjectKeys): k is keyof T {
* @returns an array of keys from `obj`
*/
export function objectKeys<T extends object>(obj: T) {
return Object.keys(obj) as Array<Keys<T>>;
return Object.keys(obj) as Array<keyof T>;
}

/**
Expand All @@ -34,7 +34,7 @@ export function Readonly<T extends object>(obj: T): DeepReadonly<T> { return obj
* @param key the name of the "tag" parameter
* @returns `obj` with the inner objects tagged with parameter `key` and the key pointing to that inner object
*/
export function taggedObject<T extends Record<ObjectKeys, object>, K extends string>(obj: T, key: K): TaggedObject<T, K> {
export function taggedObject<T extends Record<keyof any, object>, K extends string>(obj: T, key: K): TaggedObject<T, K> {
const keys = objectKeys(obj);
return keys.reduce((collection: any, k) => {
const inner: any = obj[k];
Expand Down
4 changes: 2 additions & 2 deletions src/types/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ export type AnyFunc<R = any> = (...args: any[]) => R;
* @param R the new return value of the function
* @returns the function `F` with new return value `R`
*/
export type OverwriteReturn<F extends AnyFunc, R> =
export type OverwriteReturn<F extends Function, R> =
F extends ((...x: infer T) => unknown) ? ((...x: T) => R) : never;

/**
* Returns a tuple type of a functions arguments up to 7.
* @param F a function with up to 7 arguments
* @returns a tuple containing `F`'s argument types
*/
export type ArgsAsTuple<F extends AnyFunc> =
export type ArgsAsTuple<F extends Function> =
F extends ((...x: infer T) => unknown) ? T : never;
43 changes: 18 additions & 25 deletions src/types/objects.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { False, True } from './conditionals';
import { AnyFunc } from './functions';

// -------
// Helpers
Expand All @@ -15,7 +14,7 @@ export type PlainObject = Record<string, any>;
* @returns An object formed by the key, value pairs of T
*/
export type ObjectType<T> = {
[k in Keys<T>]: T[k];
[k in keyof T]: T[k];
};
/**
* Takes two objects and returns their intersection.
Expand All @@ -34,7 +33,7 @@ export type CombineObjects<T extends object, U extends object> = ObjectType<T &
* @param K Key to query object for value
* @returns `T[K]` if the key exists, `never` otherwise
*/
export type GetKey<T, K extends ObjectKeys> = K extends Keys<T> ? T[K] : never;
export type GetKey<T, K extends keyof any> = K extends keyof T ? T[K] : never;

// ----
// Keys
Expand All @@ -55,51 +54,45 @@ export type ObjectKeys = keyof any;
* @param T type from which to get keys
* @returns keys of `T` that extend `string`
*/
export type StringKeys<T> = Exclude<Keys<T>, number | symbol>;
/**
* No different than `keyof`, but can look a bit nicer when nesting many types deep.
* @param T type from which to get keys
* @returns keys of `T` that extend `string | number | symbol`
*/
export type Keys<T> = keyof T;
export type StringKeys<T> = Exclude<keyof T, number | symbol>;
/**
* When an object has optional or readonly keys, that information is contained within the key.
* When using optional/readonly keys in another object, they will retain optional/readonly status.
* `PureKeys` will remove the optional/readonly status modifiers from keys.
* @param T type from which to get keys
* @returns keys of `T` without status modifiers (readonly/optional)
*/
export type PureKeys<T> = Record<Keys<T>, Keys<T>>[Keys<T>];
export type PureKeys<T> = Record<keyof T, keyof T>[keyof T];
/**
* Gets all of the keys that are shared between two objects.
* @param T first type from which keys will be pulled
* @param U second type from which keys will be pulled
* @returns the keys that both `T` and `U` have in common.
*/
export type SharedKeys<T, U> = Keys<T> & Keys<U>;
export type SharedKeys<T, U> = keyof T & keyof U;
/**
* Gets all keys between two objects.
* @param T first type from which keys will be pulled
* @param U second type from which keys will be pulled
* @returns the keys of `T` in addition to the keys of `U`
*/
export type AllKeys<T, U> = Keys<T> | Keys<U>;
export type AllKeys<T, U> = keyof T | keyof U;
/**
* Gets all of the keys that are different between two objects.
* This is a set difference between `Keys<T>` and `Keys<U>`.
* This is a set difference between `keyof T` and `keyof U`.
* Note that calling this with arguments reversed will have different results.
* @param T first type from which keys will be pulled
* @param U second type from which keys will be pulled
* @returns keys of `T` minus the keys of `U`
*/
export type DiffKeys<T, U> = Exclude<Keys<T>, Keys<U>>;
export type DiffKeys<T, U> = Exclude<keyof T, keyof U>;
/**
* Returns `True` if a key, `K`, is present in a type, `T`, else `False`.
* @param T type to check for existence of key `K`.
* @param K key to query `T` for
* @returns `True` if `K` is a key of `T`. Else `False`.
*/
export type HasKey<T, K extends ObjectKeys> = K extends Keys<T> ? True : False;
export type HasKey<T, K extends keyof any> = K extends keyof T ? True : False;

/**
* @param T the union to get the keys of
Expand All @@ -118,15 +111,15 @@ export type UnionKeys<T>
* @param T the object whose property values will be unionized
* @returns a union of the right-side values of `T`
*/
export type UnionizeProperties<T extends object> = T[Keys<T>];
export type UnionizeProperties<T extends object> = T[keyof T];
/**
* Gives back an object with listed keys removed.
* This is the opposite of `Pick`.
* @param T the object whose properties will be removed
* @param K the union of keys to remove from `T`
* @returns `T` with the keys `K` removed
*/
export type Omit<T extends object, K extends Keys<T>> = Pick<T, Exclude<Keys<T>, K>>;
export type Omit<T extends object, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
/**
* Returns only the shared properties between two objects.
* All shared properties must be the same type.
Expand Down Expand Up @@ -159,8 +152,8 @@ export type Merge<T extends object, U extends object> = Overwrite<T, U> & U;
* @param Key the key to add to each inner object as the tag property
* @returns a record where each key of the record is now the `Key` property of the inner object
*/
export type TaggedObject<T extends Record<ObjectKeys, object>, Key extends ObjectKeys> = {
[K in Keys<T>]: T[K] & Record<Key, K>;
export type TaggedObject<T extends Record<keyof any, object>, Key extends keyof any> = {
[K in keyof T]: T[K] & Record<Key, K>;
};

// ---------
Expand All @@ -175,7 +168,7 @@ export type TaggedObject<T extends Record<ObjectKeys, object>, Key extends Objec
export type DeepPartial<T> = Partial<{
[k in keyof T]:
T[k] extends unknown[] ? Array<DeepPartial<T[k][number]>> :
T[k] extends AnyFunc ? T[k] :
T[k] extends Function ? T[k] :
T[k] extends object ? DeepPartial<T[k]> :
T[k];
}>;
Expand All @@ -185,15 +178,15 @@ export type DeepPartial<T> = Partial<{
* @returns `T` with all fields marked required
*/
export type AllRequired<T extends object> = {
[K in Keys<T>]-?: NonNullable<T[K]>
[K in keyof T]-?: NonNullable<T[K]>
};
/**
* Mark specific keys, `K`, of `T` as required.
* @param T object whose keys will be marked required
* @param K keys of `T` that will be marked required
* @returns `T` with keys, `K`, marked as required
*/
export type Required<T extends object, K extends Keys<T>> = CombineObjects<
export type Required<T extends object, K extends keyof T> = CombineObjects<
{[k in K]-?: NonNullable<T[k]> },
Omit<T, K>
>;
Expand All @@ -203,7 +196,7 @@ export type Required<T extends object, K extends Keys<T>> = CombineObjects<
* @param K keys of `T` that will be marked optional
* @returns `T` with keys, `K`, marked as optional
*/
export type Optional<T extends object, K extends Keys<T>> = CombineObjects<
export type Optional<T extends object, K extends keyof T> = CombineObjects<
{[k in K]?: T[k] | undefined },
Omit<T, K>
>;
Expand All @@ -215,7 +208,7 @@ export type Optional<T extends object, K extends Keys<T>> = CombineObjects<
export type DeepReadonly<T> = Readonly<{
[k in keyof T]:
T[k] extends unknown[] ? ReadonlyArray<DeepReadonly<T[k][number]>> :
T[k] extends AnyFunc ? T[k] :
T[k] extends Function ? T[k] :
T[k] extends object ? DeepReadonly<T[k]> :
T[k];
}>;
Expand Down
16 changes: 7 additions & 9 deletions src/types/predicates.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
import { False, True, And, Or, Not } from './conditionals';
import { Keys } from './objects';
import { AnyFunc } from './functions';

/** no-doc */
export type KnownProblemPrototypeKeys = 'toString' | 'toLocaleString' | 'hasOwnProperty' | 'isPrototypeOf' | 'propertyIsEnumerable' | 'constructor' | 'valueOf';
/** no-doc */
export type ArrayPrototypeKeys = keyof unknown[];
/** no-doc */
export type NumberPrototypeKeys = Keys<number>;
export type NumberPrototypeKeys = keyof number;
/** no-doc */
export type BooleanPrototypeKeys = Keys<false>;
export type BooleanPrototypeKeys = keyof false;
/** no-doc */
export type StringPrototypeKeys = Keys<string>;
export type StringPrototypeKeys = keyof string;
/** no-doc */
export type ObjectPrototypeKeys = Keys<Object>; // tslint:disable-line
export type ObjectPrototypeKeys = keyof Object;
/** no-doc */
export type FunctionPrototypeKeys = Keys<Function>; // tslint:disable-line
export type FunctionPrototypeKeys = keyof Function;

export type IsNever<S extends string> = Not<(Record<S, True> & Record<string, False>)[S]>;
export type IsType<T, X> = X extends T ? True : False;
Expand All @@ -24,8 +22,8 @@ export type IsNumber<T> = T extends number ? True : False;
export type IsString<T> = T extends string ? True : False;
export type IsFunction<T> =
Or<
T extends AnyFunc ? True : False,
T extends Function ? True : False>; // tslint:disable-line
T extends Function ? True : False,
Copy link
Collaborator

Choose a reason for hiding this comment

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

The find/replace made this condition redundant.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Merp. Good catch. Not sure how I missed it on my final scan

T extends Function ? True : False>;

export type IsStringFunction<T extends string> = And<IsString<T>, IsNever<T>>;
export type IsBoolean<T> = T extends boolean ? True : False;
Expand Down
13 changes: 0 additions & 13 deletions test/objects/Keys.test.ts

This file was deleted.

2 changes: 1 addition & 1 deletion test/prototypes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ test('Can check if a type is a string', t => {

test('Can check if a type is a function', t => {
assert<IsFunction<func>, True>(t);
assert<IsFunction<Function>, True>(t); // tslint:disable-line
assert<IsFunction<Function>, True>(t);

assert<IsFunction<obj>, False>(t);
assert<IsFunction<str>, False>(t);
Expand Down
1 change: 1 addition & 0 deletions tslint.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
],
"rules": {
"arrow-parens": false,
"ban-types": false,
"curly": false,
"indent": [
true,
Expand Down