expect-type
Advanced tools
Comparing version 0.18.0 to 0.19.0
@@ -0,18 +1,60 @@ | ||
/** | ||
* Negates a boolean type. | ||
*/ | ||
export declare type Not<T extends boolean> = T extends true ? false : true; | ||
/** | ||
* Returns `true` if at least one of the types in the | ||
* {@linkcode Types} array is `true`, otherwise returns `false`. | ||
*/ | ||
export declare type Or<Types extends boolean[]> = Types[number] extends false ? false : true; | ||
/** | ||
* Checks if all the boolean types in the {@linkcode Types} array are `true`. | ||
*/ | ||
export declare type And<Types extends boolean[]> = Types[number] extends true ? true : false; | ||
/** | ||
* Represents an equality type that returns {@linkcode Right} if | ||
* {@linkcode Left} is `true`, | ||
* otherwise returns the negation of {@linkcode Right}. | ||
*/ | ||
export declare type Eq<Left extends boolean, Right extends boolean> = Left extends true ? Right : Not<Right>; | ||
/** | ||
* Represents the exclusive OR operation on a tuple of boolean types. | ||
* Returns `true` if exactly one of the boolean types is `true`, | ||
* otherwise returns `false`. | ||
*/ | ||
export declare type Xor<Types extends [boolean, boolean]> = Not<Eq<Types[0], Types[1]>>; | ||
declare const secret: unique symbol; | ||
declare type Secret = typeof secret; | ||
/** | ||
* Checks if the given type is `never`. | ||
*/ | ||
export declare type IsNever<T> = [T] extends [never] ? true : false; | ||
/** | ||
* Checks if the given type is `any`. | ||
*/ | ||
export declare type IsAny<T> = [T] extends [Secret] ? Not<IsNever<T>> : false; | ||
/** | ||
* Determines if the given type is `unknown`. | ||
*/ | ||
export declare type IsUnknown<T> = [unknown] extends [T] ? Not<IsAny<T>> : false; | ||
/** | ||
* Determines if a type is either `never` or `any`. | ||
*/ | ||
export declare type IsNeverOrAny<T> = Or<[IsNever<T>, IsAny<T>]>; | ||
/** | ||
* Determines the printable type representation for a given type. | ||
*/ | ||
export declare type PrintType<T> = IsUnknown<T> extends true ? 'unknown' : IsNever<T> extends true ? 'never' : IsAny<T> extends true ? never : boolean extends T ? 'boolean' : T extends boolean ? `literal boolean: ${T}` : string extends T ? 'string' : T extends string ? `literal string: ${T}` : number extends T ? 'number' : T extends number ? `literal number: ${T}` : T extends null ? 'null' : T extends undefined ? 'undefined' : T extends (...args: any[]) => any ? 'function' : '...'; | ||
/** Subjective "useful" keys from a type. For objects it's just `keyof` but for tuples/arrays it's the number keys | ||
/** | ||
* Subjective "useful" keys from a type. For objects it's just `keyof` but for | ||
* tuples/arrays it's the number keys. | ||
* | ||
* @example | ||
* ```ts | ||
* UsefulKeys<{a: 1; b: 2}> // 'a' | 'b' | ||
* | ||
* UsefulKeys<['a', 'b']> // '0' | '1' | ||
* | ||
* UsefulKeys<string[]> // number | ||
* ``` | ||
*/ | ||
@@ -26,5 +68,9 @@ export declare type UsefulKeys<T> = T extends any[] ? { | ||
/** | ||
* Recursively walk a type and replace it with a branded type related to the original. This is useful for | ||
* equality-checking stricter than `A extends B ? B extends A ? true : false : false`, because it detects | ||
* the difference between a few edge-case types that vanilla typescript doesn't by default: | ||
* Represents a deeply branded type. | ||
* | ||
* Recursively walk a type and replace it with a branded type related to the | ||
* original. This is useful for equality-checking stricter than | ||
* `A extends B ? B extends A ? true : false : false`, because it detects the | ||
* difference between a few edge-case types that vanilla typescript | ||
* doesn't by default: | ||
* - `any` vs `unknown` | ||
@@ -34,4 +80,5 @@ * - `{ readonly a: string }` vs `{ a: string }` | ||
* | ||
* Note: not very performant for complex types - this should only be used when you know you need it. If doing | ||
* an equality check, it's almost always better to use `StrictEqualUsingTSInternalIdenticalToOperator`. | ||
* __Note__: not very performant for complex types - this should only be used | ||
* when you know you need it. If doing an equality check, it's almost always | ||
* better to use {@linkcode StrictEqualUsingTSInternalIdenticalToOperator}. | ||
*/ | ||
@@ -72,6 +119,15 @@ export declare type DeepBrand<T> = IsNever<T> extends true ? { | ||
}; | ||
/** | ||
* Extracts the keys from a type that are required (not optional). | ||
*/ | ||
export declare type RequiredKeys<T> = Extract<{ | ||
[K in keyof T]-?: {} extends Pick<T, K> ? never : K; | ||
}[keyof T], keyof T>; | ||
/** | ||
* Gets the keys of an object type that are optional. | ||
*/ | ||
export declare type OptionalKeys<T> = Exclude<keyof T, RequiredKeys<T>>; | ||
/** | ||
* Extracts the keys from a type that are not readonly. | ||
*/ | ||
export declare type ReadonlyKeys<T> = Extract<{ | ||
@@ -84,8 +140,22 @@ [K in keyof T]-?: ReadonlyEquivalent<{ | ||
}[keyof T], keyof T>; | ||
/** | ||
* Determines if two types, are equivalent in a `readonly` manner. | ||
*/ | ||
declare type ReadonlyEquivalent<X, Y> = Extends<(<T>() => T extends X ? true : false), (<T>() => T extends Y ? true : false)>; | ||
/** Returns true if `L extends R`. Explicitly checks for `never` since that can give unexpected results. */ | ||
/** | ||
* Checks if one type extends another. | ||
*/ | ||
export declare type Extends<L, R> = IsNever<L> extends true ? IsNever<R> : [L] extends [R] ? true : false; | ||
export declare type ExtendsUsingBranding<L, R> = Extends<DeepBrand<L>, DeepBrand<R>>; | ||
export declare type ExtendsExcludingAnyOrNever<L, R> = IsAny<L> extends true ? IsAny<R> : Extends<L, R>; | ||
/** | ||
* Checks if two types are strictly equal using | ||
* the TypeScript internal identical-to operator. | ||
* | ||
* @see {@link https://github.com/microsoft/TypeScript/issues/55188#issuecomment-1656328122 much history} | ||
*/ | ||
declare type StrictEqualUsingTSInternalIdenticalToOperator<L, R> = (<T>() => T extends (L & T) | T ? true : false) extends <T>() => T extends (R & T) | T ? true : false ? IsNever<L> extends IsNever<R> ? true : false : false; | ||
/** | ||
* Checks if two types are strictly equal using branding. | ||
*/ | ||
export declare type StrictEqualUsingBranding<Left, Right> = And<[ | ||
@@ -95,4 +165,19 @@ ExtendsUsingBranding<Left, Right>, | ||
]>; | ||
/** | ||
* Represents a type that checks if two types are equal, using | ||
* a hopefully performant approach. | ||
* It first checks if the types are strictly equal using | ||
* {@linkcode StrictEqualUsingTSInternalIdenticalToOperator}. | ||
* If they are not strictly equal, it falls back to using the | ||
* {@linkcode StrictEqualUsingBranding} type. | ||
*/ | ||
export declare type HopefullyPerformantEqual<Left, Right> = StrictEqualUsingTSInternalIdenticalToOperator<Left, Right> extends true ? true : StrictEqualUsingBranding<Left, Right>; | ||
export declare type Params<Actual> = Actual extends (...args: infer P) => any ? P : never; | ||
/** | ||
* Extracts the parameter types from a function type. | ||
*/ | ||
export declare type Params<Actual> = Actual extends (...args: infer ParameterTypes) => any ? ParameterTypes : never; | ||
/** | ||
* Represents the constructor parameters of a class or constructor function. | ||
* If the constructor takes no arguments, an empty array is returned. | ||
*/ | ||
export declare type ConstructorParams<Actual> = Actual extends new (...args: infer P) => any ? Actual extends new () => any ? P | [] : P : never; | ||
@@ -103,8 +188,29 @@ declare const mismatch: unique symbol; | ||
}; | ||
/** A type which should match anything passed as a value but *doesn't* match `Mismatch` - helps TypeScript select the right overload for `toEqualTypeOf` and `toMatchTypeOf`. */ | ||
/** | ||
* A type which should match anything passed as a value but *doesn't* | ||
* match {@linkcode Mismatch}. It helps TypeScript select the right overload | ||
* for {@linkcode PositiveExpectTypeOf.toEqualTypeOf `.toEqualTypeOf()`} and | ||
* {@linkcode PositiveExpectTypeOf.toMatchTypeOf `.toMatchTypeOf()`}. | ||
*/ | ||
declare const avalue: unique symbol; | ||
/** | ||
* Represents a value that can be of various types. | ||
*/ | ||
declare type AValue = { | ||
[avalue]?: undefined; | ||
} | string | number | boolean | symbol | bigint | null | undefined | void; | ||
/** | ||
* Represents the type of mismatched arguments between | ||
* the actual result and the expected result. | ||
* | ||
* If {@linkcode ActualResult} and {@linkcode ExpectedResult} are equivalent, | ||
* the type resolves to an empty tuple `[]`, indicating no mismatch. | ||
* If they are not equivalent, it resolves to a tuple containing the element | ||
* {@linkcode Mismatch}, signifying a discrepancy between | ||
* the expected and actual results. | ||
*/ | ||
declare type MismatchArgs<ActualResult extends boolean, ExpectedResult extends boolean> = Eq<ActualResult, ExpectedResult> extends true ? [] : [Mismatch]; | ||
/** | ||
* Represents the options for the {@linkcode ExpectTypeOf} function. | ||
*/ | ||
export interface ExpectTypeOfOptions { | ||
@@ -188,2 +294,6 @@ positive: boolean; | ||
}; | ||
/** | ||
* Represents a scolder function that checks if the result of an expecter | ||
* matches the specified options. | ||
*/ | ||
declare type Scolder<Expecter extends { | ||
@@ -194,2 +304,6 @@ result: boolean; | ||
}> = Expecter['result'] extends Options['positive'] ? () => true : Options['positive'] extends true ? Expecter : Inverted<Expecter>; | ||
/** | ||
* Represents the positive assertion methods available for type checking in the | ||
* {@linkcode expectTypeOf()} utility. | ||
*/ | ||
export interface PositiveExpectTypeOf<Actual> extends BaseExpectTypeOf<Actual, { | ||
@@ -200,17 +314,197 @@ positive: true; | ||
toEqualTypeOf: { | ||
/** | ||
* Uses TypeScript's internal technique to check for type "identicalness". | ||
* | ||
* It will check if the types are fully equal to each other. | ||
* It will not fail if two objects have different values, but the same type. | ||
* It will fail however if an object is missing a property. | ||
* | ||
* **_Unexpected failure_**? For a more permissive but less performant | ||
* check that accommodates for equivalent intersection types, | ||
* use {@linkcode branded `.branded.toEqualTypeOf()`}. | ||
* @see {@link https://github.com/mmkal/expect-type#why-is-my-assertion-failing The documentation for details}. | ||
* | ||
* @example | ||
* <caption>Using generic type argument syntax</caption> | ||
* ```ts | ||
* expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: number }>() | ||
* | ||
* expectTypeOf({ a: 1, b: 1 }).not.toEqualTypeOf<{ a: number }>() | ||
* ``` | ||
* | ||
* @example | ||
* <caption>Using inferred type syntax by passing a value</caption> | ||
* ```ts | ||
* expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 1 }) | ||
* | ||
* expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 2 }) | ||
* ``` | ||
* | ||
* @param value - The value to compare against the expected type. | ||
* @param MISMATCH - The mismatch arguments. | ||
* @returns `true`. | ||
*/ | ||
<Expected extends StrictEqualUsingTSInternalIdenticalToOperator<Actual, Expected> extends true ? unknown : MismatchInfo<Actual, Expected>>(value: Expected & AValue, // reason for `& AValue`: make sure this is only the selected overload when the end-user passes a value for an inferred typearg. The `Mismatch` type does match `AValue`. | ||
...MISMATCH: MismatchArgs<StrictEqualUsingTSInternalIdenticalToOperator<Actual, Expected>, true>): true; | ||
/** | ||
* Uses TypeScript's internal technique to check for type "identicalness". | ||
* | ||
* It will check if the types are fully equal to each other. | ||
* It will not fail if two objects have different values, but the same type. | ||
* It will fail however if an object is missing a property. | ||
* | ||
* **_Unexpected failure_**? For a more permissive but less performant | ||
* check that accommodates for equivalent intersection types, | ||
* use {@linkcode branded `.branded.toEqualTypeOf()`}. | ||
* @see {@link https://github.com/mmkal/expect-type#why-is-my-assertion-failing The documentation for details}. | ||
* | ||
* @example | ||
* <caption>Using generic type argument syntax</caption> | ||
* ```ts | ||
* expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: number }>() | ||
* | ||
* expectTypeOf({ a: 1, b: 1 }).not.toEqualTypeOf<{ a: number }>() | ||
* ``` | ||
* | ||
* @example | ||
* <caption>Using inferred type syntax by passing a value</caption> | ||
* ```ts | ||
* expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 1 }) | ||
* | ||
* expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 2 }) | ||
* ``` | ||
* | ||
* @param MISMATCH - The mismatch arguments. | ||
* @returns `true`. | ||
*/ | ||
<Expected extends StrictEqualUsingTSInternalIdenticalToOperator<Actual, Expected> extends true ? unknown : MismatchInfo<Actual, Expected>>(...MISMATCH: MismatchArgs<StrictEqualUsingTSInternalIdenticalToOperator<Actual, Expected>, true>): true; | ||
}; | ||
toMatchTypeOf: { | ||
/** | ||
* A less strict version of {@linkcode toEqualTypeOf `.toEqualTypeOf()`} | ||
* that allows for extra properties. | ||
* This is roughly equivalent to an `extends` constraint | ||
* in a function type argument. | ||
* | ||
* @example | ||
* <caption>Using generic type argument syntax</caption> | ||
* ```ts | ||
* expectTypeOf({ a: 1, b: 1 }).toMatchTypeOf<{ a: number }>() | ||
* ``` | ||
* | ||
* @example | ||
* <caption>Using inferred type syntax by passing a value</caption> | ||
* ```ts | ||
* expectTypeOf({ a: 1, b: 1 }).toMatchTypeOf({ a: 2 }) | ||
* ``` | ||
* | ||
* @param value - The value to compare against the expected type. | ||
* @param MISMATCH - The mismatch arguments. | ||
* @returns `true`. | ||
*/ | ||
<Expected extends Extends<Actual, Expected> extends true ? unknown : MismatchInfo<Actual, Expected>>(value: Expected & AValue, // reason for `& AValue`: make sure this is only the selected overload when the end-user passes a value for an inferred typearg. The `Mismatch` type does match `AValue`. | ||
...MISMATCH: MismatchArgs<Extends<Actual, Expected>, true>): true; | ||
/** | ||
* A less strict version of {@linkcode toEqualTypeOf `.toEqualTypeOf()`} | ||
* that allows for extra properties. | ||
* This is roughly equivalent to an `extends` constraint | ||
* in a function type argument. | ||
* | ||
* @example | ||
* <caption>Using generic type argument syntax</caption> | ||
* ```ts | ||
* expectTypeOf({ a: 1, b: 1 }).toMatchTypeOf<{ a: number }>() | ||
* ``` | ||
* | ||
* @example | ||
* <caption>Using inferred type syntax by passing a value</caption> | ||
* ```ts | ||
* expectTypeOf({ a: 1, b: 1 }).toMatchTypeOf({ a: 2 }) | ||
* ``` | ||
* | ||
* @param MISMATCH - The mismatch arguments. | ||
* @returns `true`. | ||
*/ | ||
<Expected extends Extends<Actual, Expected> extends true ? unknown : MismatchInfo<Actual, Expected>>(...MISMATCH: MismatchArgs<Extends<Actual, Expected>, true>): true; | ||
}; | ||
toHaveProperty: <K extends keyof Actual>(key: K, ...MISMATCH: MismatchArgs<Extends<K, keyof Actual>, true>) => K extends keyof Actual ? PositiveExpectTypeOf<Actual[K]> : true; | ||
/** | ||
* Checks whether an object has a given property. | ||
* | ||
* @example | ||
* <caption>check that properties exist</caption> | ||
* ```ts | ||
* const obj = {a: 1, b: ''} | ||
* | ||
* expectTypeOf(obj).toHaveProperty('a') | ||
* | ||
* expectTypeOf(obj).not.toHaveProperty('c') | ||
* ``` | ||
* | ||
* @param key - The property key to check for. | ||
* @param MISMATCH - The mismatch arguments. | ||
* @returns `true`. | ||
*/ | ||
toHaveProperty: <KeyType extends keyof Actual>(key: KeyType, ...MISMATCH: MismatchArgs<Extends<KeyType, keyof Actual>, true>) => KeyType extends keyof Actual ? PositiveExpectTypeOf<Actual[KeyType]> : true; | ||
/** | ||
* Inverts the result of the following assertions. | ||
* | ||
* @example | ||
* ```ts | ||
* expectTypeOf({ a: 1 }).not.toMatchTypeOf({ b: 1 }) | ||
* ``` | ||
*/ | ||
not: NegativeExpectTypeOf<Actual>; | ||
/** | ||
* Intersection types can cause issues with | ||
* {@linkcode toEqualTypeOf `.toEqualTypeOf()`}: | ||
* ```ts | ||
* // ❌ The following line doesn't compile, even though the types are arguably the same. | ||
* expectTypeOf<{ a: 1 } & { b: 2 }>().toEqualTypeOf<{ a: 1; b: 2 }>() | ||
* ``` | ||
* This helper works around this problem by using | ||
* a more permissive but less performant check. | ||
* | ||
* __Note__: This comes at a performance cost, and can cause the compiler | ||
* to 'give up' if used with excessively deep types, so use sparingly. | ||
* | ||
* @see {@link https://github.com/mmkal/expect-type/pull/21 Reference} | ||
*/ | ||
branded: { | ||
/** | ||
* Uses TypeScript's internal technique to check for type "identicalness". | ||
* | ||
* It will check if the types are fully equal to each other. | ||
* It will not fail if two objects have different values, but the same type. | ||
* It will fail however if an object is missing a property. | ||
* | ||
* **_Unexpected failure_**? For a more permissive but less performant | ||
* check that accommodates for equivalent intersection types, | ||
* use {@linkcode PositiveExpectTypeOf.branded `.branded.toEqualTypeOf()`}. | ||
* @see {@link https://github.com/mmkal/expect-type#why-is-my-assertion-failing The documentation for details}. | ||
* | ||
* @example | ||
* <caption>Using generic type argument syntax</caption> | ||
* ```ts | ||
* expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: number }>() | ||
* | ||
* expectTypeOf({ a: 1, b: 1 }).not.toEqualTypeOf<{ a: number }>() | ||
* ``` | ||
* | ||
* @example | ||
* <caption>Using inferred type syntax by passing a value</caption> | ||
* ```ts | ||
* expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 1 }) | ||
* | ||
* expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 2 }) | ||
* ``` | ||
* | ||
* @param MISMATCH - The mismatch arguments. | ||
* @returns `true`. | ||
*/ | ||
toEqualTypeOf: <Expected extends StrictEqualUsingBranding<Actual, Expected> extends true ? unknown : MismatchInfo<Actual, Expected>>(...MISMATCH: MismatchArgs<StrictEqualUsingBranding<Actual, Expected>, true>) => true; | ||
}; | ||
} | ||
/** | ||
* Represents the negative expectation type for the {@linkcode Actual} type. | ||
*/ | ||
export interface NegativeExpectTypeOf<Actual> extends BaseExpectTypeOf<Actual, { | ||
@@ -220,50 +514,516 @@ positive: false; | ||
toEqualTypeOf: { | ||
/** | ||
* Uses TypeScript's internal technique to check for type "identicalness". | ||
* | ||
* It will check if the types are fully equal to each other. | ||
* It will not fail if two objects have different values, but the same type. | ||
* It will fail however if an object is missing a property. | ||
* | ||
* **_Unexpected failure_**? For a more permissive but less performant | ||
* check that accommodates for equivalent intersection types, | ||
* use {@linkcode PositiveExpectTypeOf.branded `.branded.toEqualTypeOf()`}. | ||
* @see {@link https://github.com/mmkal/expect-type#why-is-my-assertion-failing The documentation for details}. | ||
* | ||
* @example | ||
* <caption>Using generic type argument syntax</caption> | ||
* ```ts | ||
* expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: number }>() | ||
* | ||
* expectTypeOf({ a: 1, b: 1 }).not.toEqualTypeOf<{ a: number }>() | ||
* ``` | ||
* | ||
* @example | ||
* <caption>Using inferred type syntax by passing a value</caption> | ||
* ```ts | ||
* expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 1 }) | ||
* | ||
* expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 2 }) | ||
* ``` | ||
* | ||
* @param value - The value to compare against the expected type. | ||
* @param MISMATCH - The mismatch arguments. | ||
* @returns `true`. | ||
*/ | ||
<Expected>(value: Expected & AValue, ...MISMATCH: MismatchArgs<StrictEqualUsingTSInternalIdenticalToOperator<Actual, Expected>, false>): true; | ||
/** | ||
* Uses TypeScript's internal technique to check for type "identicalness". | ||
* | ||
* It will check if the types are fully equal to each other. | ||
* It will not fail if two objects have different values, but the same type. | ||
* It will fail however if an object is missing a property. | ||
* | ||
* **_Unexpected failure_**? For a more permissive but less performant | ||
* check that accommodates for equivalent intersection types, | ||
* use {@linkcode PositiveExpectTypeOf.branded `.branded.toEqualTypeOf()`}. | ||
* @see {@link https://github.com/mmkal/expect-type#why-is-my-assertion-failing The documentation for details}. | ||
* | ||
* @example | ||
* <caption>Using generic type argument syntax</caption> | ||
* ```ts | ||
* expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: number }>() | ||
* | ||
* expectTypeOf({ a: 1, b: 1 }).not.toEqualTypeOf<{ a: number }>() | ||
* ``` | ||
* | ||
* @example | ||
* <caption>Using inferred type syntax by passing a value</caption> | ||
* ```ts | ||
* expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 1 }) | ||
* | ||
* expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 2 }) | ||
* ``` | ||
* | ||
* @param MISMATCH - The mismatch arguments. | ||
* @returns `true`. | ||
*/ | ||
<Expected>(...MISMATCH: MismatchArgs<StrictEqualUsingTSInternalIdenticalToOperator<Actual, Expected>, false>): true; | ||
}; | ||
toMatchTypeOf: { | ||
/** | ||
* A less strict version of | ||
* {@linkcode PositiveExpectTypeOf.toEqualTypeOf `.toEqualTypeOf()`} | ||
* that allows for extra properties. | ||
* This is roughly equivalent to an `extends` constraint | ||
* in a function type argument. | ||
* | ||
* @example | ||
* <caption>Using generic type argument syntax</caption> | ||
* ```ts | ||
* expectTypeOf({ a: 1, b: 1 }).toMatchTypeOf<{ a: number }>() | ||
* ``` | ||
* | ||
* @example | ||
* <caption>Using inferred type syntax by passing a value</caption> | ||
* ```ts | ||
* expectTypeOf({ a: 1, b: 1 }).toMatchTypeOf({ a: 2 }) | ||
* ``` | ||
* | ||
* @param value - The value to compare against the expected type. | ||
* @param MISMATCH - The mismatch arguments. | ||
* @returns `true`. | ||
*/ | ||
<Expected>(value: Expected & AValue, // reason for `& AValue`: make sure this is only the selected overload when the end-user passes a value for an inferred typearg. The `Mismatch` type does match `AValue`. | ||
...MISMATCH: MismatchArgs<Extends<Actual, Expected>, false>): true; | ||
/** | ||
* A less strict version of | ||
* {@linkcode PositiveExpectTypeOf.toEqualTypeOf `.toEqualTypeOf()`} | ||
* that allows for extra properties. | ||
* This is roughly equivalent to an `extends` constraint | ||
* in a function type argument. | ||
* | ||
* @example | ||
* <caption>Using generic type argument syntax</caption> | ||
* ```ts | ||
* expectTypeOf({ a: 1, b: 1 }).toMatchTypeOf<{ a: number }>() | ||
* ``` | ||
* | ||
* @example | ||
* <caption>Using inferred type syntax by passing a value</caption> | ||
* ```ts | ||
* expectTypeOf({ a: 1, b: 1 }).toMatchTypeOf({ a: 2 }) | ||
* ``` | ||
* | ||
* @param MISMATCH - The mismatch arguments. | ||
* @returns `true`. | ||
*/ | ||
<Expected>(...MISMATCH: MismatchArgs<Extends<Actual, Expected>, false>): true; | ||
}; | ||
toHaveProperty: <K extends string | number | symbol>(key: K, ...MISMATCH: MismatchArgs<Extends<K, keyof Actual>, false>) => true; | ||
/** | ||
* Checks whether an object has a given property. | ||
* | ||
* @example | ||
* <caption>check that properties exist</caption> | ||
* ```ts | ||
* const obj = {a: 1, b: ''} | ||
* | ||
* expectTypeOf(obj).toHaveProperty('a') | ||
* | ||
* expectTypeOf(obj).not.toHaveProperty('c') | ||
* ``` | ||
* | ||
* @param key - The property key to check for. | ||
* @param MISMATCH - The mismatch arguments. | ||
* @returns `true`. | ||
*/ | ||
toHaveProperty: <KeyType extends string | number | symbol>(key: KeyType, ...MISMATCH: MismatchArgs<Extends<KeyType, keyof Actual>, false>) => true; | ||
} | ||
/** | ||
* Represents a conditional type that selects either | ||
* {@linkcode PositiveExpectTypeOf} or {@linkcode NegativeExpectTypeOf} based | ||
* on the value of the `positive` property in the {@linkcode Options} type. | ||
*/ | ||
export declare type ExpectTypeOf<Actual, Options extends { | ||
positive: boolean; | ||
}> = Options['positive'] extends true ? PositiveExpectTypeOf<Actual> : NegativeExpectTypeOf<Actual>; | ||
/** | ||
* Represents the base interface for the | ||
* {@linkcode expectTypeOf()} function. | ||
* Provides a set of assertion methods to perform type checks on a value. | ||
*/ | ||
export interface BaseExpectTypeOf<Actual, Options extends { | ||
positive: boolean; | ||
}> { | ||
/** | ||
* Checks whether the type of the value is `any`. | ||
*/ | ||
toBeAny: Scolder<ExpectAny<Actual>, Options>; | ||
/** | ||
* Checks whether the type of the value is `unknown`. | ||
*/ | ||
toBeUnknown: Scolder<ExpectUnknown<Actual>, Options>; | ||
/** | ||
* Checks whether the type of the value is `never`. | ||
*/ | ||
toBeNever: Scolder<ExpectNever<Actual>, Options>; | ||
/** | ||
* Checks whether the type of the value is `function`. | ||
*/ | ||
toBeFunction: Scolder<ExpectFunction<Actual>, Options>; | ||
/** | ||
* Checks whether the type of the value is `object`. | ||
*/ | ||
toBeObject: Scolder<ExpectObject<Actual>, Options>; | ||
/** | ||
* Checks whether the type of the value is an {@linkcode Array}. | ||
*/ | ||
toBeArray: Scolder<ExpectArray<Actual>, Options>; | ||
/** | ||
* Checks whether the type of the value is `number`. | ||
*/ | ||
toBeNumber: Scolder<ExpectNumber<Actual>, Options>; | ||
/** | ||
* Checks whether the type of the value is `string`. | ||
*/ | ||
toBeString: Scolder<ExpectString<Actual>, Options>; | ||
/** | ||
* Checks whether the type of the value is `boolean`. | ||
*/ | ||
toBeBoolean: Scolder<ExpectBoolean<Actual>, Options>; | ||
/** | ||
* Checks whether the type of the value is `void`. | ||
*/ | ||
toBeVoid: Scolder<ExpectVoid<Actual>, Options>; | ||
/** | ||
* Checks whether the type of the value is `symbol`. | ||
*/ | ||
toBeSymbol: Scolder<ExpectSymbol<Actual>, Options>; | ||
/** | ||
* Checks whether the type of the value is `null`. | ||
*/ | ||
toBeNull: Scolder<ExpectNull<Actual>, Options>; | ||
/** | ||
* Checks whether the type of the value is `undefined`. | ||
*/ | ||
toBeUndefined: Scolder<ExpectUndefined<Actual>, Options>; | ||
/** | ||
* Checks whether the type of the value is `null` or `undefined`. | ||
*/ | ||
toBeNullable: Scolder<ExpectNullable<Actual>, Options>; | ||
/** | ||
* Checks whether a function is callable with the given parameters. | ||
* | ||
* __Note__: You cannot negate this assertion with | ||
* {@linkcode PositiveExpectTypeOf.not `.not`} you need to use | ||
* `ts-expect-error` instead. | ||
* | ||
* @example | ||
* ```ts | ||
* const f = (a: number) => [a, a] | ||
* | ||
* expectTypeOf(f).toBeCallableWith(1) | ||
* ``` | ||
* | ||
* __Known Limitation__: This assertion will likely fail if you try to use it | ||
* with a generic function or an overload. | ||
* @see {@link https://github.com/mmkal/expect-type/issues/50 This issue} for an example and a workaround. | ||
* | ||
* @param args - The arguments to check for callability. | ||
* @returns `true`. | ||
*/ | ||
toBeCallableWith: Options['positive'] extends true ? (...args: Params<Actual>) => true : never; | ||
/** | ||
* Checks whether a class is constructible with the given parameters. | ||
* | ||
* @example | ||
* ```ts | ||
* expectTypeOf(Date).toBeConstructibleWith('1970') | ||
* | ||
* expectTypeOf(Date).toBeConstructibleWith(0) | ||
* | ||
* expectTypeOf(Date).toBeConstructibleWith(new Date()) | ||
* | ||
* expectTypeOf(Date).toBeConstructibleWith() | ||
* ``` | ||
* | ||
* @param args - The arguments to check for constructibility. | ||
* @returns `true`. | ||
*/ | ||
toBeConstructibleWith: Options['positive'] extends true ? (...args: ConstructorParams<Actual>) => true : never; | ||
/** | ||
* Equivalent to the {@linkcode Extract} utility type. | ||
* Helps narrow down complex union types. | ||
* | ||
* @example | ||
* ```ts | ||
* type ResponsiveProp<T> = T | T[] | { xs?: T; sm?: T; md?: T } | ||
* | ||
* interface CSSProperties { | ||
* margin?: string | ||
* padding?: string | ||
* } | ||
* | ||
* function getResponsiveProp<T>(_props: T): ResponsiveProp<T> { | ||
* return {} | ||
* } | ||
* | ||
* const cssProperties: CSSProperties = { margin: '1px', padding: '2px' } | ||
* | ||
* expectTypeOf(getResponsiveProp(cssProperties)) | ||
* .extract<{ xs?: any }>() // extracts the last type from a union | ||
* .toEqualTypeOf<{ | ||
* xs?: CSSProperties | ||
* sm?: CSSProperties | ||
* md?: CSSProperties | ||
* }>() | ||
* | ||
* expectTypeOf(getResponsiveProp(cssProperties)) | ||
* .extract<unknown[]>() // extracts an array from a union | ||
* .toEqualTypeOf<CSSProperties[]>() | ||
* ``` | ||
* | ||
* __Note__: If no type is found in the union, it will return `never`. | ||
* | ||
* @param v - The type to extract from the union. | ||
* @returns The type after extracting the type from the union. | ||
*/ | ||
extract: <V>(v?: V) => ExpectTypeOf<Extract<Actual, V>, Options>; | ||
/** | ||
* Equivalent to the {@linkcode Exclude} utility type. | ||
* Removes types from a union. | ||
* | ||
* @example | ||
* ```ts | ||
* type ResponsiveProp<T> = T | T[] | { xs?: T; sm?: T; md?: T } | ||
* | ||
* interface CSSProperties { | ||
* margin?: string | ||
* padding?: string | ||
* } | ||
* | ||
* function getResponsiveProp<T>(_props: T): ResponsiveProp<T> { | ||
* return {} | ||
* } | ||
* | ||
* const cssProperties: CSSProperties = { margin: '1px', padding: '2px' } | ||
* | ||
* expectTypeOf(getResponsiveProp(cssProperties)) | ||
* .exclude<unknown[]>() | ||
* .exclude<{ xs?: unknown }>() // or just `.exclude<unknown[] | { xs?: unknown }>()` | ||
* .toEqualTypeOf<CSSProperties>() | ||
* ``` | ||
*/ | ||
exclude: <V>(v?: V) => ExpectTypeOf<Exclude<Actual, V>, Options>; | ||
pick: <K extends keyof Actual>(v?: K) => ExpectTypeOf<Pick<Actual, K>, Options>; | ||
omit: <K extends keyof Actual>(v?: K) => ExpectTypeOf<Omit<Actual, K>, Options>; | ||
parameter: <K extends keyof Params<Actual>>(number: K) => ExpectTypeOf<Params<Actual>[K], Options>; | ||
/** | ||
* Equivalent to the {@linkcode Pick} utility type. | ||
* Helps select a subset of properties from an object type. | ||
* | ||
* @example | ||
* ```ts | ||
* interface Person { | ||
* name: string | ||
* age: number | ||
* } | ||
* | ||
* expectTypeOf<Person>() | ||
* .pick<'name'>() | ||
* .toEqualTypeOf<{ name: string }>() | ||
* ``` | ||
* | ||
* @param keyToPick - The property key to pick. | ||
* @returns The type after picking the property. | ||
*/ | ||
pick: <KeyToPick extends keyof Actual>(keyToPick?: KeyToPick) => ExpectTypeOf<Pick<Actual, KeyToPick>, Options>; | ||
/** | ||
* Equivalent to the {@linkcode Omit} utility type. | ||
* Helps remove a subset of properties from an object type. | ||
* | ||
* @example | ||
* ```ts | ||
* interface Person { | ||
* name: string | ||
* age: number | ||
* } | ||
* | ||
* expectTypeOf<Person>().omit<'name'>().toEqualTypeOf<{ age: number }>() | ||
* ``` | ||
* | ||
* @param keyToOmit - The property key to omit. | ||
* @returns The type after omitting the property. | ||
*/ | ||
omit: <KeyToOmit extends keyof Actual | (PropertyKey & Record<never, never>)>(keyToOmit?: KeyToOmit) => ExpectTypeOf<Omit<Actual, KeyToOmit>, Options>; | ||
/** | ||
* Extracts a certain function argument with `.parameter(number)` call to | ||
* perform other assertions on it. | ||
* | ||
* @example | ||
* ```ts | ||
* function foo(a: number, b: string) { | ||
* return [a, b] | ||
* } | ||
* | ||
* expectTypeOf(foo).parameter(0).toBeNumber() | ||
* | ||
* expectTypeOf(foo).parameter(1).toBeString() | ||
* ``` | ||
* | ||
* @param index - The index of the parameter to extract. | ||
* @returns The extracted parameter type. | ||
*/ | ||
parameter: <Index extends keyof Params<Actual>>(index: Index) => ExpectTypeOf<Params<Actual>[Index], Options>; | ||
/** | ||
* Equivalent to the {@linkcode Parameters} utility type. | ||
* Extracts function parameters to perform assertions on its value. | ||
* Parameters are returned as an array. | ||
* | ||
* @example | ||
* ```ts | ||
* function noParam() {} | ||
* | ||
* function hasParam(s: string) {} | ||
* | ||
* expectTypeOf(noParam).parameters.toEqualTypeOf<[]>() | ||
* | ||
* expectTypeOf(hasParam).parameters.toEqualTypeOf<[string]>() | ||
* ``` | ||
*/ | ||
parameters: ExpectTypeOf<Params<Actual>, Options>; | ||
/** | ||
* Equivalent to the {@linkcode ConstructorParameters} utility type. | ||
* Extracts constructor parameters as an array of values and | ||
* perform assertions on them with this method. | ||
* | ||
* @example | ||
* ```ts | ||
* expectTypeOf(Date).constructorParameters.toEqualTypeOf< | ||
* [] | [string | number | Date] | ||
* >() | ||
* ``` | ||
*/ | ||
constructorParameters: ExpectTypeOf<ConstructorParams<Actual>, Options>; | ||
/** | ||
* Equivalent to the {@linkcode ThisParameterType} utility type. | ||
* Extracts the `this` parameter of a function to | ||
* perform assertions on its value. | ||
* | ||
* @example | ||
* ```ts | ||
* function greet(this: { name: string }, message: string) { | ||
* return `Hello ${this.name}, here's your message: ${message}` | ||
* } | ||
* | ||
* expectTypeOf(greet).thisParameter.toEqualTypeOf<{ name: string }>() | ||
* ``` | ||
*/ | ||
thisParameter: ExpectTypeOf<ThisParameterType<Actual>, Options>; | ||
/** | ||
* Equivalent to the {@linkcode InstanceType} utility type. | ||
* Extracts the instance type of a class to perform assertions on. | ||
* | ||
* @example | ||
* ```ts | ||
* expectTypeOf(Date).instance.toHaveProperty('toISOString') | ||
* ``` | ||
*/ | ||
instance: Actual extends new (...args: any[]) => infer I ? ExpectTypeOf<I, Options> : never; | ||
/** | ||
* Equivalent to the {@linkcode ReturnType} utility type. | ||
* Extracts the return type of a function. | ||
* | ||
* @example | ||
* ```ts | ||
* expectTypeOf(() => {}).returns.toBeVoid() | ||
* | ||
* expectTypeOf((a: number) => [a, a]).returns.toEqualTypeOf([1, 2]) | ||
* ``` | ||
*/ | ||
returns: Actual extends (...args: any[]) => infer R ? ExpectTypeOf<R, Options> : never; | ||
resolves: Actual extends PromiseLike<infer R> ? ExpectTypeOf<R, Options> : never; | ||
items: Actual extends ArrayLike<infer R> ? ExpectTypeOf<R, Options> : never; | ||
/** | ||
* Extracts resolved value of a Promise, | ||
* so you can perform other assertions on it. | ||
* | ||
* @example | ||
* ```ts | ||
* async function asyncFunc() { | ||
* return 123 | ||
* } | ||
* | ||
* expectTypeOf(asyncFunc).returns.resolves.toBeNumber() | ||
* | ||
* expectTypeOf(Promise.resolve('string')).resolves.toBeString() | ||
* ``` | ||
* | ||
* Type Equivalent: | ||
* ```ts | ||
* type Resolves<PromiseType> = PromiseType extends PromiseLike<infer ResolvedType> | ||
* ? ResolvedType | ||
* : never | ||
* ``` | ||
*/ | ||
resolves: Actual extends PromiseLike<infer ResolvedType> ? ExpectTypeOf<ResolvedType, Options> : never; | ||
/** | ||
* Extracts array item type to perform assertions on. | ||
* | ||
* @example | ||
* ```ts | ||
* expectTypeOf([1, 2, 3]).items.toEqualTypeOf<number>() | ||
* | ||
* expectTypeOf([1, 2, 3]).items.not.toEqualTypeOf<string>() | ||
* ``` | ||
* | ||
* __Type Equivalent__: | ||
* ```ts | ||
* type Items<ArrayType> = ArrayType extends ArrayLike<infer ItemType> | ||
* ? ItemType | ||
* : never | ||
* ``` | ||
*/ | ||
items: Actual extends ArrayLike<infer ItemType> ? ExpectTypeOf<ItemType, Options> : never; | ||
/** | ||
* Extracts the type guarded by a function to perform assertions on. | ||
* | ||
* @example | ||
* ```ts | ||
* function isString(v: any): v is string { | ||
* return typeof v === 'string' | ||
* } | ||
* | ||
* expectTypeOf(isString).guards.toBeString() | ||
* ``` | ||
*/ | ||
guards: Actual extends (v: any, ...args: any[]) => v is infer T ? ExpectTypeOf<T, Options> : never; | ||
/** | ||
* Extracts the type asserted by a function to perform assertions on. | ||
* | ||
* @example | ||
* ```ts | ||
* function assertNumber(v: any): asserts v is number { | ||
* if (typeof v !== 'number') | ||
* throw new TypeError('Nope !') | ||
* } | ||
* | ||
* expectTypeOf(assertNumber).asserts.toBeNumber() | ||
* ``` | ||
*/ | ||
asserts: Actual extends (v: any, ...args: any[]) => asserts v is infer T ? unknown extends T ? never : ExpectTypeOf<T, Options> : never; | ||
} | ||
/** | ||
* Represents a function that allows asserting the expected type of a value. | ||
*/ | ||
export declare type _ExpectTypeOf = { | ||
/** | ||
* Asserts the expected type of a value. | ||
* | ||
* @param actual - The actual value being asserted. | ||
* @returns An object representing the expected type assertion. | ||
*/ | ||
<Actual>(actual: Actual): ExpectTypeOf<Actual, { | ||
@@ -273,2 +1033,7 @@ positive: true; | ||
}>; | ||
/** | ||
* Asserts the expected type of a value without providing an actual value. | ||
* | ||
* @returns An object representing the expected type assertion. | ||
*/ | ||
<Actual>(): ExpectTypeOf<Actual, { | ||
@@ -275,0 +1040,0 @@ positive: true; |
@@ -6,3 +6,8 @@ "use strict"; | ||
const mismatch = Symbol('mismatch'); | ||
/** A type which should match anything passed as a value but *doesn't* match `Mismatch` - helps TypeScript select the right overload for `toEqualTypeOf` and `toMatchTypeOf`. */ | ||
/** | ||
* A type which should match anything passed as a value but *doesn't* | ||
* match {@linkcode Mismatch}. It helps TypeScript select the right overload | ||
* for {@linkcode PositiveExpectTypeOf.toEqualTypeOf `.toEqualTypeOf()`} and | ||
* {@linkcode PositiveExpectTypeOf.toMatchTypeOf `.toMatchTypeOf()`}. | ||
*/ | ||
const avalue = Symbol('avalue'); | ||
@@ -62,3 +67,3 @@ const inverted = Symbol('inverted'); | ||
const obj = { | ||
/* eslint-disable mmkal/@typescript-eslint/no-unsafe-assignment */ | ||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */ | ||
toBeAny: fn, | ||
@@ -82,3 +87,3 @@ toBeUnknown: fn, | ||
toBeConstructibleWith: fn, | ||
/* eslint-enable mmkal/@typescript-eslint/no-unsafe-assignment */ | ||
/* eslint-enable @typescript-eslint/no-unsafe-assignment */ | ||
extract: exports.expectTypeOf, | ||
@@ -85,0 +90,0 @@ exclude: exports.expectTypeOf, |
{ | ||
"name": "expect-type", | ||
"version": "0.18.0", | ||
"version": "0.19.0", | ||
"engines": { | ||
@@ -30,19 +30,18 @@ "node": ">=12.0.0" | ||
"devDependencies": { | ||
"@types/jest": "29.5.7", | ||
"@types/node": "^14.0.0", | ||
"eslint": "8.53.0", | ||
"eslint-plugin-mmkal": "0.1.2", | ||
"jest": "28.1.3", | ||
"eslint": "^8.57.0", | ||
"eslint-plugin-mmkal": "0.4.1", | ||
"np": "^10.0.0", | ||
"strip-ansi": "6.0.1", | ||
"ts-jest": "28.0.8", | ||
"ts-morph": "16.0.0", | ||
"typescript": "4.8.2" | ||
"typescript": "4.8.2", | ||
"vitest": "^1.4.0" | ||
}, | ||
"scripts": { | ||
"eslint": "eslint --ext '.ts,.js,.md'", | ||
"lint": "tsc && eslint .", | ||
"eslint": "eslint --max-warnings 0", | ||
"lint": "tsc && pnpm eslint .", | ||
"type-check": "tsc", | ||
"build": "tsc -p tsconfig.lib.json", | ||
"test": "jest" | ||
"test": "vitest run" | ||
} | ||
} |
# expect-type | ||
[![CI](https://github.com/mmkal/expect-type/actions/workflows/ci.yml/badge.svg)](https://github.com/mmkal/expect-type/actions/workflows/ci.yml) | ||
[![](https://byob.yarr.is/mmkal/expect-type/coverage)](https://github.com/mmkal/expect-type/actions/workflows/ci.yml) | ||
![npm](https://img.shields.io/npm/dt/expect-type) | ||
@@ -11,14 +10,12 @@ | ||
```typescript | ||
```ts | ||
import {expectTypeOf} from 'expect-type' | ||
import {foo, bar} from '../foo' | ||
import {expectTypeOf} from 'expect-type' | ||
test('foo types', () => { | ||
// make sure `foo` has type {a: number} | ||
expectTypeOf(foo).toMatchTypeOf<{a: number}>() | ||
// make sure `foo` has type {a: number} | ||
expectTypeOf(foo).toMatchTypeOf<{a: number}>() | ||
// make sure `bar` is a function taking a string: | ||
expectTypeOf(bar).parameter(0).toBeString() | ||
expectTypeOf(bar).returns.not.toBeAny() | ||
}) | ||
// make sure `bar` is a function taking a string: | ||
expectTypeOf(bar).parameter(0).toBeString() | ||
expectTypeOf(bar).returns.not.toBeAny() | ||
``` | ||
@@ -43,2 +40,3 @@ | ||
- [Jest & `eslint-plugin-jest`](#jest--eslint-plugin-jest) | ||
- [Limitations](#limitations) | ||
- [Similar projects](#similar-projects) | ||
@@ -68,2 +66,4 @@ - [Comparison](#comparison) | ||
eslint prettier/prettier: ["warn", { "singleQuote": true, "semi": false, "arrowParens": "avoid", "trailingComma": "es5", "bracketSpacing": false, "endOfLine": "auto", "printWidth": 100 }] | ||
```typescript | ||
@@ -159,2 +159,4 @@ expectTypeOf({a: 1}).toEqualTypeOf<{a: number}>() | ||
eslint-disable-next-line vitest/valid-title | ||
```typescript | ||
@@ -651,7 +653,8 @@ expectTypeOf(() => 1).toBeFunction() | ||
#### Jest & `eslint-plugin-jest` | ||
If you're using Jest along with `eslint-plugin-jest`, you may get warnings from the [`jest/expect-expect`](https://github.com/jest-community/eslint-plugin-jest/blob/master/docs/rules/expect-expect.md) rule, complaining that "Test has no assertions" for tests that only use `expectTypeOf()`. | ||
If you're using Jest along with `eslint-plugin-jest`, and you put assertions inside `test(...)` definitions, you may get warnings from the [`jest/expect-expect`](https://github.com/jest-community/eslint-plugin-jest/blob/master/docs/rules/expect-expect.md) rule, complaining that "Test has no assertions" for tests that only use `expectTypeOf()`. | ||
To remove this warning, configure the ESlint rule to consider `expectTypeOf` as an assertion: | ||
```js | ||
```json | ||
"rules": { | ||
@@ -671,2 +674,11 @@ // ... | ||
### Limitations | ||
A summary of some of the limitations of this library. Some of these is documented more fully elsewhere. | ||
1. Intersection types can result in failures when the expected and actual types are not identically defined, even when they are effectively identical. See [Why is my assertion failing](#why-is-my-assertion-failing) for details. TL;DR: use `.brand` in these cases - and accept the perf hit that it comes with. | ||
1. `toBeCallableWith` will likely fail if you try to use it with a generic function or an overload. See [this issue](https://github.com/mmkal/expect-type/issues/50) for an example and how to work around. | ||
1. (For now) overloaded functions might trip up the `.parameter` and `.parameters` helpers. This matches how the built-in typescript helper `Parameters<...>` works. This may be improved in the future though ([see related issue](https://github.com/mmkal/expect-type/issues/30)). | ||
1. `expectTypeOf(this).toEqualTypeOf(this)` inside class methods does not work. | ||
## Similar projects | ||
@@ -673,0 +685,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
82826
8
1156
718
1