Skip to content

Commit

Permalink
✨ Add String#charAt function
Browse files Browse the repository at this point in the history
  • Loading branch information
TomokiMiyauci committed Jul 1, 2021
1 parent 052db81 commit b9bb4c8
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 0 deletions.
22 changes: 22 additions & 0 deletions string/char_at.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2021-present the Core-fn authors. All rights reserved. MIT license.
import { curry } from "../deps.ts";
import { charAt as _charAt } from "../uncurry/string/char_at.ts";

/**
* Returns the character at the specified index.
* @param pos - The zero-based index of the desired character
* @param val - Any `String`
* @returns The result of `val.charAt(pos)`
*
* @example
* ```ts
* charAt(0, 'hello') // 'h'
* charAt(4, 'hello') // 'o'
* charAt(100, 'hello') // ''
* ```
*
* @beta
*/
const charAt = curry(_charAt);

export { charAt };
9 changes: 9 additions & 0 deletions string/char_at_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright 2021-present the Core-fn authors. All rights reserved. MIT license.
import { charAt } from "./char_at.ts";
import { assertEqualsType } from "../dev_deps.ts";

Deno.test("charAt", () => {
assertEqualsType<(val: string) => string>(charAt(0));
assertEqualsType<string>(charAt(0)(""));
assertEqualsType<string>(charAt(0, ""));
});
1 change: 1 addition & 0 deletions string/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ export { repeat } from "./repeat.ts";
export { trimEnd } from "./trim_end.ts";
export { trimStart } from "./trim_start.ts";
export { match } from "./match.ts";
export { charAt } from "./char_at.ts";
41 changes: 41 additions & 0 deletions uncurry/string/char_at.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2021-present the Core-fn authors. All rights reserved. MIT license.

type IsNegative<T extends number | bigint> = `${T}` extends `-${infer _}` ? true
: false;
type String2Array<T extends string> = T extends "" ? []
: T extends `${infer F}${infer R}` ? [F, ...String2Array<R>]
: string[];

/**
* @internal
*/
type CharAt<T extends number, U extends string> = IsNegative<T> extends true
? ""
: String2Array<U>[T] extends infer R ? R extends undefined ? "" : R
: string;

/**
* Returns the character at the specified index.
* @param pos - The zero-based index of the desired character
* @param val - Any `String`
* @returns The result of `val.charAt(pos)`
*
* @remarks
* Due to the TypeScript recursion limit, the maximum number of valid characters is `23`. If you want to adapt a `string` longer than that, need to cast it to a `string` type.
*
* @example
* ```ts
* charAt(0, 'hello') // 'h'
* charAt(4, 'hello') // 'o'
* charAt(100, 'hello') // ''
* ```
*
* @beta
*/
const charAt = <T extends number, U extends string>(
pos: T,
val: U,
): CharAt<T, U> => val.charAt(pos) as CharAt<T, U>;

export { charAt };
export type { CharAt };
40 changes: 40 additions & 0 deletions uncurry/string/char_at_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright 2021-present the Core-fn authors. All rights reserved. MIT license.
import { assertEquals, assertEqualsType } from "../../dev_deps.ts";
import { CharAt, charAt } from "./char_at.ts";

Deno.test("charAt", () => {
const table: [number, string, string][] = [
[0, "", ""],
[0, "abc", "a"],
[1, "abc", "b"],
[2, "abc", "c"],
[3, "abc", ""],
[100, "abc", ""],
[-1, "abc", ""],
[-100, "abc", ""],
[-0, "abc", "a"],
[-0, "", ""],
];
table.forEach(([pos, val, expected]) => {
assertEquals(
charAt(pos, val),
expected,
`charAt(${pos}, ${val}) -> ${expected}`,
);
});

assertEqualsType<"", CharAt<0, "">>();
assertEqualsType<"", CharAt<1, "">>();
assertEqualsType<"", CharAt<2, "">>();
assertEqualsType<"a", CharAt<0, "a">>();
assertEqualsType<"", CharAt<1, "a">>();
assertEqualsType<"a", CharAt<0, "ab">>();
assertEqualsType<"b", CharAt<1, "ab">>();
assertEqualsType<"", CharAt<2, "ab">>();
assertEqualsType<"", CharAt<-1, "">>();
assertEqualsType<"", CharAt<-1, "a">>();
assertEqualsType<"", CharAt<-1, "ab">>();
assertEqualsType<"", CharAt<-100, "ab">>();
assertEqualsType<"", CharAt<100, "ab">>();
assertEqualsType<"a", CharAt<-0, "ab">>();
});
1 change: 1 addition & 0 deletions uncurry/string/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export { startsWith } from "./starts_with.ts";
export { endsWith } from "./ends_with.ts";
export { repeat } from "./repeat.ts";
export { match } from "./match.ts";
export { charAt } from "./char_at.ts";

0 comments on commit b9bb4c8

Please sign in to comment.