-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8703823
commit 2f456ec
Showing
10 changed files
with
366 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@khanacademy/wonder-stuff-core": minor | ||
--- | ||
|
||
Re-add entries, keys, and values wrappers |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// @flow | ||
import {entries} from "../entries"; | ||
|
||
describe("#entries", () => { | ||
it("should call Object.entries with the given object", () => { | ||
// Arrange | ||
const entriesSpy = jest.spyOn(Object, "entries"); | ||
const obj = { | ||
a: 1, | ||
b: "2", | ||
c: [3, 4], | ||
}; | ||
|
||
// Act | ||
entries(obj); | ||
|
||
// Assert | ||
expect(entriesSpy).toHaveBeenCalledWith(obj); | ||
}); | ||
|
||
it("should return the result of Object.entries", () => { | ||
// Arrange | ||
const obj = { | ||
a: 1, | ||
b: "2", | ||
c: [3, 4], | ||
}; | ||
jest.spyOn(Object, "entries").mockReturnValueOnce([ | ||
["e", 1], | ||
["f", 2], | ||
["g", 3], | ||
]); | ||
|
||
// Act | ||
const result = entries(obj); | ||
|
||
// Assert | ||
expect(result).toEqual([ | ||
["e", 1], | ||
["f", 2], | ||
["g", 3], | ||
]); | ||
}); | ||
}); |
69 changes: 69 additions & 0 deletions
69
packages/wonder-stuff-core/src/__tests__/entries.typestest.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import {entries} from "../entries"; | ||
|
||
{ | ||
// should type returned array element as tuples of keys as string subtype | ||
const obj1 = { | ||
a: 1, | ||
b: "2", | ||
c: [3, 4], | ||
}; | ||
|
||
const entries1 = entries(obj1); | ||
|
||
// This works because the keys are all strings | ||
const [_]: [string, unknown] = entries1[0]; | ||
} | ||
|
||
{ | ||
// should type returned array element as tuples supertype of keys | ||
const obj2 = { | ||
a: 1, | ||
b: "2", | ||
c: [3, 4], | ||
} as const; | ||
const entries2 = entries(obj2); | ||
|
||
// It would be nice if this worked, but TypeScript's library definition | ||
// defines the first item in the tuples returned by Object.entries() to | ||
// be `string`s. | ||
// @ts-expect-error: "a" | "b" | "c" is not assignable to string | ||
const [_]: ["a" | "b" | "c", unknown] = entries2[0]; | ||
|
||
// This errors because we try to get a key of only one type. | ||
// @ts-expect-error: "a" is not assignable to string | ||
const [__]: ["a", unknown] = entries2[0]; | ||
} | ||
|
||
{ | ||
// should type returned array element as tuples of values as supertype | ||
const obj1 = { | ||
a: 1, | ||
b: "2", | ||
c: [3, 4], | ||
}; | ||
|
||
const entries1 = entries(obj1); | ||
|
||
// This works because the keys are all strings, and the values are a | ||
// supertype of all the value types in the object. | ||
const [_, __]: [string, number | string | Array<number>] = entries1[0]; | ||
|
||
// @ts-expect-error: This errors because not all values are a number. | ||
const [___, ____]: [string, number] = entries1[0]; | ||
} | ||
|
||
{ | ||
// should work with class instances | ||
class Foo { | ||
a: string; | ||
b: string; | ||
constructor(a: string, b: string) { | ||
this.a = a; | ||
this.b = b; | ||
} | ||
} | ||
const foo = new Foo("hello", "world"); | ||
|
||
// This should not be erroring. | ||
const _ = entries(foo); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import {keys} from "../keys"; | ||
|
||
describe("#keys", () => { | ||
it("should call Object.keys with the given object", () => { | ||
// Arrange | ||
const keysSpy = jest.spyOn(Object, "keys"); | ||
const obj = { | ||
a: 1, | ||
b: "2", | ||
c: [3, 4], | ||
}; | ||
|
||
// Act | ||
keys(obj); | ||
|
||
// Assert | ||
expect(keysSpy).toHaveBeenCalledWith(obj); | ||
}); | ||
|
||
it("should return the result of Object.keys", () => { | ||
// Arrange | ||
const obj = { | ||
a: 1, | ||
b: "2", | ||
c: [3, 4], | ||
}; | ||
jest.spyOn(Object, "keys").mockReturnValueOnce(["THE RESULT"]); | ||
|
||
// Act | ||
const result = keys(obj); | ||
|
||
// Assert | ||
expect(result).toEqual(["THE RESULT"]); | ||
}); | ||
}); |
57 changes: 57 additions & 0 deletions
57
packages/wonder-stuff-core/src/__tests__/keys.typestest.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import {keys} from "../keys"; | ||
|
||
{ | ||
// should type returned array element as subtype of string | ||
const obj1 = { | ||
a: 1, | ||
b: "2", | ||
}; | ||
|
||
const keys1 = keys(obj1); | ||
const _: string = keys1[0]; | ||
} | ||
|
||
{ | ||
// should type returned array element as supertype of keys | ||
const obj2 = { | ||
a: 1, | ||
b: "2", | ||
c: [3, 4], | ||
} as const; | ||
|
||
// It would be nice if this worked, but TypeScript's library definition | ||
// defines the return type of Object.keys() to be Array<string>. | ||
const keys2bad = keys(obj2); | ||
// @ts-expect-error: string is not assignable to "a" | "b" | "c" | ||
const _: "a" | "b" | "c" = keys2bad[0]; | ||
|
||
// @ts-expect-error: This errors because we try to get a key of only one type. | ||
const __: "a" = keys2bad[0]; | ||
} | ||
|
||
{ | ||
// should work with more specific object types | ||
const obj3: Record<string, string> = { | ||
a: "1", | ||
b: "2", | ||
}; | ||
|
||
// This should not be erroring. | ||
const _ = keys(obj3); | ||
} | ||
|
||
{ | ||
// should work with class instances | ||
class Foo { | ||
a: string; | ||
b: string; | ||
constructor(a: string, b: string) { | ||
this.a = a; | ||
this.b = b; | ||
} | ||
} | ||
const foo = new Foo("hello", "world"); | ||
|
||
// This should not be erroring. | ||
const _ = keys(foo); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import {values} from "../values"; | ||
|
||
describe("#values", () => { | ||
it("should call Object.values with the given object", () => { | ||
// Arrange | ||
const valuesSpy = jest.spyOn(Object, "values"); | ||
const obj = { | ||
a: 1, | ||
b: "2", | ||
c: [3, 4], | ||
}; | ||
|
||
// Act | ||
values(obj); | ||
|
||
// Assert | ||
expect(valuesSpy).toHaveBeenCalledWith(obj); | ||
}); | ||
|
||
it("should return the result of Object.values", () => { | ||
// Arrange | ||
const obj = { | ||
a: 1, | ||
b: "2", | ||
c: [3, 4], | ||
}; | ||
jest.spyOn(Object, "values").mockReturnValue(["THE RESULT"]); | ||
|
||
// Act | ||
const result = values(obj); | ||
|
||
// Assert | ||
expect(result).toEqual(["THE RESULT"]); | ||
}); | ||
}); |
71 changes: 71 additions & 0 deletions
71
packages/wonder-stuff-core/src/__tests__/values.typestest.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import {values} from "../values"; | ||
|
||
{ | ||
// should type returned array element with union of value types of passed object | ||
const obj1 = { | ||
a: 1, | ||
b: "2", | ||
c: [3, 4], | ||
}; | ||
const obj1Values = values(obj1); | ||
|
||
// This works because the variable is typed to all the possible value types. | ||
const _: number | string | Array<number> = obj1Values[0]; | ||
|
||
// @ts-expect-error: This errors because the variable is only typed to string, but | ||
// the value could be a number, string, or array of numbers. | ||
const __: string = obj1Values[1]; | ||
} | ||
|
||
{ | ||
// should work with explicit object-as-map types | ||
const map1: {[key: string]: number} = { | ||
a: 1, | ||
b: 2, | ||
c: 3, | ||
}; | ||
const map1Values = values(map1); | ||
|
||
// This works because the variable is typed to number. | ||
const _: number = map1Values[0]; | ||
|
||
// @ts-expect-error: This errors because the variable is typed to string, and that | ||
// is not a number. | ||
const __: string = map1Values[1]; | ||
} | ||
|
||
{ | ||
// should return type Array<empty> for empty object | ||
const emptyObj = {}; | ||
const _: Array<never> = values(emptyObj); | ||
} | ||
|
||
{ | ||
// should error if passed object values do not match parameterized type | ||
const obj2 = { | ||
a: 1, | ||
b: "2", | ||
}; | ||
|
||
// @ts-expect-error: This errors because the return type of values() is not Array<number> | ||
const _: Array<number> = values(obj2); | ||
|
||
// @ts-expect-error: This errors because the object does not have values that are all numbers. | ||
const __ = values<number>(obj2); | ||
} | ||
|
||
{ | ||
// should work with class instances | ||
class Foo { | ||
a: string; | ||
b: string; | ||
constructor(a: string, b: string) { | ||
this.a = a; | ||
this.b = b; | ||
} | ||
} | ||
const foo = new Foo("hello", "world"); | ||
|
||
// This should not be erroring. | ||
const _ = values(foo); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
/** | ||
* Return an array of key/value tuples for an object. | ||
* | ||
* @param {{[s: string]: T}} obj The object for which the values are | ||
* to be returned. | ||
* @returns {Array<[string, T]>} An array of key/value tuples for the object. | ||
*/ | ||
// NOTE(kevinb): This type was copied from TypeScript's library definitions. | ||
export const entries: { | ||
<T>( | ||
obj: | ||
| { | ||
[s: string]: T; | ||
} | ||
| ArrayLike<T>, | ||
): [string, T][]; | ||
// eslint-disable-next-line @typescript-eslint/ban-types | ||
(obj: {}): [string, any][]; | ||
} = (obj: any) => Object.entries(obj); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
/** | ||
* Return an array of the enumerable keys of an object. | ||
* | ||
* @param {$ReadOnly<interface {[string]: mixed}>} obj The object for which the values are | ||
* to be returned. | ||
* @returns {Array<$Keys<O>>} An array of the enumerable keys of an object. | ||
*/ | ||
// NOTE(kevinb): This type was copied from TypeScript's library definitions. | ||
// eslint-disable-next-line @typescript-eslint/ban-types | ||
export function keys(obj: {}): string[] { | ||
return Object.keys(obj); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
/** | ||
* Return an array of the enumerable property values of an object. | ||
* | ||
* @param {$ReadOnly<interface {[mixed]: V}>} obj The object for which the values are | ||
* to be returned. | ||
* @returns {Array<V>} An array of the enumerable property values of the object. | ||
*/ | ||
// NOTE(kevinb): This type was copied from TypeScript's library definitions. | ||
export const values: { | ||
<T>( | ||
obj: | ||
| { | ||
[s: string]: T; | ||
} | ||
| ArrayLike<T>, | ||
): T[]; | ||
// eslint-disable-next-line @typescript-eslint/ban-types | ||
(obj: {}): any[]; | ||
} = (obj: any) => Object.values(obj); |