diff --git a/packages/utils/src/functions/getHashFragment.ts b/packages/utils/src/functions/getHashFragment.ts index b4ffb67..2e7664c 100644 --- a/packages/utils/src/functions/getHashFragment.ts +++ b/packages/utils/src/functions/getHashFragment.ts @@ -7,6 +7,7 @@ import { isString } from './isString' * * @param url * @returns {string} + * @throws {URIError} 内部で利用している `decodeURIComponent()` がエラーをスローする可能性がある * @example * // 返値: hash fragment * getHashFragment('https://localhost:8080?test=32#hash+fragment') diff --git a/packages/utils/src/functions/getQueryString.ts b/packages/utils/src/functions/getQueryString.ts index 10011a2..4d873d3 100644 --- a/packages/utils/src/functions/getQueryString.ts +++ b/packages/utils/src/functions/getQueryString.ts @@ -7,6 +7,7 @@ import { removeHashFragment } from './removeHashFragment' * * @param url * @returns {string} + * @throws {URIError} 内部で利用している `decodeURIComponent()` がエラーをスローする可能性がある * @example * // 返値: ?test1=32&test2=ア * getQueryString('https://localhost:8080?test1=32&test2=%E3%82%A2#fragment') diff --git a/packages/utils/src/functions/safeDecodeURIComponent.ts b/packages/utils/src/functions/safeDecodeURIComponent.ts new file mode 100644 index 0000000..1d463c7 --- /dev/null +++ b/packages/utils/src/functions/safeDecodeURIComponent.ts @@ -0,0 +1,28 @@ +/** + * decodeURIComponent()で発生する例外をキャッチして、例外が発生した場合はエラーオブジェクトを返却する + * + * @param value + * @returns {{ data: string; error: null } | { data: null; error: URIError }} + * @example + * const { data, error } = safeDecodeURIComponent('foo%20bar') // => { data: 'foo bar', error: null } + * if (error) { + * console.error(error) + * } else { + * console.log(data) // => 'foo bar' + * } + */ +export function safeDecodeURIComponent(value: string): { data: string; error: null } | { data: null; error: URIError } { + try { + const data = decodeURIComponent(value) + return { data, error: null } + } catch (e) { + return { + data: null, + /** + * try中で発生する例外はdecodeURIComponentの仕様によるものなので、SyntaxErrorでアサーションしている + * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#exceptions} + */ + error: e as URIError, + } + } +} diff --git a/packages/utils/src/functions/safeEncodeURIComponent.ts b/packages/utils/src/functions/safeEncodeURIComponent.ts new file mode 100644 index 0000000..df9c599 --- /dev/null +++ b/packages/utils/src/functions/safeEncodeURIComponent.ts @@ -0,0 +1,28 @@ +/** + * encodeURIComponent()で発生する例外をキャッチして、例外が発生した場合はエラーオブジェクトを返却する + * + * @param value + * @returns {{ data: string; error: null } | { data: null; error: URIError }} + * @example + * const { data, error } = safeEncodeURIComponent('foo bar') // => { data: 'foo%20bar', error: null } + * if (error) { + * console.error(error) + * } else { + * console.log(data) // => 'foo%20bar' + * } + */ +export function safeEncodeURIComponent(value: string): { data: string; error: null } | { data: null; error: URIError } { + try { + const data = encodeURIComponent(value) + return { data, error: null } + } catch (e) { + return { + data: null, + /** + * try中で発生する例外はencodeURIComponentの仕様によるものなので、SyntaxErrorでアサーションしている + * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent#exceptions} + */ + error: e as SyntaxError, + } + } +} diff --git a/packages/utils/src/functions/safeJsonParse.ts b/packages/utils/src/functions/safeJsonParse.ts new file mode 100644 index 0000000..6fb8db9 --- /dev/null +++ b/packages/utils/src/functions/safeJsonParse.ts @@ -0,0 +1,36 @@ +/** + * JSON.parse()で発生する例外をキャッチして、例外が発生した場合はエラーオブジェクトを返す + * + * 型変数 `T` はJSON.parse()でパースするデータの型を指定する + * + * ※ ただし、型ガードは行わないため、呼び出し元で型ガードを適宜実施すること + * + * @param value + * @param options + * @returns {{ data: T; error: null } | { data: null; error: SyntaxError }} + * @example + * const { data, error } = safeJsonParse<{ foo: string }>('{"foo": "bar"}') // => { data: { foo: 'bar' }, error: null } + * if (error) { + * console.error(error) + * } else { + * console.log(data) // => { foo: 'bar' } + * } + */ +export function safeJsonParse( + value: string, + options?: { reviver?: Parameters[1] } +): { data: T; error: null } | { data: null; error: SyntaxError } { + try { + const data = JSON.parse(value, options?.reviver) + return { data, error: null } + } catch (e) { + return { + data: null, + /** + * try中で発生する例外はJSON.parseの仕様によるものなので、SyntaxErrorでアサーションしている + * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#exceptions} + */ + error: e as SyntaxError, + } + } +} diff --git a/packages/utils/src/functions/safeJsonStringify.ts b/packages/utils/src/functions/safeJsonStringify.ts new file mode 100644 index 0000000..0bfdff3 --- /dev/null +++ b/packages/utils/src/functions/safeJsonStringify.ts @@ -0,0 +1,35 @@ +/** + * JSON.stringify()で発生する例外をキャッチして、例外が発生した場合はエラーオブジェクトを返す + * + * @param value + * @param options + * @returns {{ data: string; error: null } | { data: null; error: TypeError }} + * @example + * const { data, error } = safeJsonStringify({ foo: 'bar' }) // => { data: '{"foo":"bar"}', error: null } + * if (error) { + * console.error(error) + * } else { + * console.log(data) // => '{"foo":"bar"}' + * } + */ +export function safeJsonStringify( + value: T, + options?: { + replacer?: Parameters[1] + space?: Parameters[2] + } +): { data: string; error: null } | { data: null; error: TypeError } { + try { + const data = JSON.stringify(value, options?.replacer, options?.space) + return { data, error: null } + } catch (e) { + return { + data: null, + /** + * try中で発生する例外はJSON.stringifyの仕様によるものなので、TypeErrorでアサーションしている + * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#exceptions} + */ + error: e as TypeError, + } + } +} diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index bbcfea2..5a85ea7 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -39,6 +39,10 @@ export * from './functions/replaceHwAlphanumericsWithFw' export * from './functions/replaceNewLineChars' export * from './functions/replaceSpacesWithTab' export * from './functions/replaceTabWithSpaces' +export * from './functions/safeDecodeURIComponent' +export * from './functions/safeEncodeURIComponent' +export * from './functions/safeJsonParse' +export * from './functions/safeJsonStringify' export * from './functions/separateArray' export * from './functions/strf' export * from './functions/withRootRelativePath' diff --git a/packages/utils/src/types/utils.ts b/packages/utils/src/types/utils.ts index 24c6294..5b9874a 100644 --- a/packages/utils/src/types/utils.ts +++ b/packages/utils/src/types/utils.ts @@ -126,3 +126,21 @@ export type ExactNotMatchTypeKeys = keyof Omit export type RequiredAtLeastOne = Pick> & Partial> & (K extends keyof T ? { [_K in K]-?: Pick, _K> }[K] : never) + +/** + * オブジェクトの全フィールドの型からundefined,nullを除外した型を得る + * + * ※ ネストしたオブジェクトのフィールドに対しては適用されない + * + * @example + * type Post = { + * id: `post_${number}` + * title: string + * body: string | undefined + * author: { name: string; age: number | undefined } + * createdAt: Date + * updatedAt?: Date | null + * } + * type NewPost = NonNullishFields // { id: `post_${number}`; title: string; body: string; author: { name: string; age: number | undefined }; createdAt: Date; updatedAt: Date } + */ +export type NonNullishFields = { [K in keyof T]-?: NonNullable } diff --git a/packages/utils/tests/functions/getHashFragment.spec.ts b/packages/utils/tests/functions/getHashFragment.spec.ts index fc30084..c8a102a 100644 --- a/packages/utils/tests/functions/getHashFragment.spec.ts +++ b/packages/utils/tests/functions/getHashFragment.spec.ts @@ -1,4 +1,4 @@ -import { test, expect } from 'vitest' +import { expect, test } from 'vitest' import { getHashFragment } from '../../src' test('getHashFragment()', () => { @@ -8,4 +8,5 @@ test('getHashFragment()', () => { expect(getHashFragment('https://localhost:8080?test=32#hash_fragment')).toBe('hash_fragment') expect(getHashFragment('https://localhost:8080?test=32#hash+fragment')).toBe('hash fragment') expect(getHashFragment('https://localhost:8080?test=32#%E3%83%86%E3%82%B9%E3%83%88')).toBe('テスト') + expect(() => getHashFragment('https://localhost:8080?test=32#%E0%A4%A')).toThrowError(URIError) }) diff --git a/packages/utils/tests/functions/getQueryString.spec.ts b/packages/utils/tests/functions/getQueryString.spec.ts index 4ce1664..9651131 100644 --- a/packages/utils/tests/functions/getQueryString.spec.ts +++ b/packages/utils/tests/functions/getQueryString.spec.ts @@ -1,4 +1,4 @@ -import { test, expect } from 'vitest' +import { expect, test } from 'vitest' import { getQueryString } from '../../src' test('getQueryString()', () => { @@ -8,4 +8,5 @@ test('getQueryString()', () => { expect(getQueryString('https://localhost:8080?#test1=3+2&test2=%E3%82%A2')).toBe('?') expect(getQueryString('https://localhost:8080#?test1=3+2&test2=%E3%82%A2')).toBe('') expect(getQueryString('https://localhost:8080/#?test1=32&test2=%E3%82%A2')).toBe('') + expect(() => getQueryString('https://localhost:8080/?test1=32&test2=%E0%A4%A')).toThrowError(URIError) }) diff --git a/packages/utils/tests/functions/safeDecodeURIComponent.spec.ts b/packages/utils/tests/functions/safeDecodeURIComponent.spec.ts new file mode 100644 index 0000000..3ad8ee2 --- /dev/null +++ b/packages/utils/tests/functions/safeDecodeURIComponent.spec.ts @@ -0,0 +1,16 @@ +import { describe, expect, test } from 'vitest' +import { safeDecodeURIComponent } from '../../src' + +describe('safeDecodeURIComponent()', () => { + test('デコードされた値が返ってくる', () => { + expect(safeDecodeURIComponent('%3Fx%3Dtest')).toEqual({ data: '?x=test', error: null }) + expect(safeDecodeURIComponent('foo%20bar')).toEqual({ data: 'foo bar', error: null }) + expect(safeDecodeURIComponent('%E3%83%86%E3%82%B9%E3%83%88')).toEqual({ data: 'テスト', error: null }) + }) + + test('URIErrorが返ってくる', () => { + const { data, error } = safeDecodeURIComponent('%') + expect(data).toBeNull() + expect(error).toBeInstanceOf(URIError) + }) +}) diff --git a/packages/utils/tests/functions/safeEncodeURIComponent.spec.ts b/packages/utils/tests/functions/safeEncodeURIComponent.spec.ts new file mode 100644 index 0000000..d163fc8 --- /dev/null +++ b/packages/utils/tests/functions/safeEncodeURIComponent.spec.ts @@ -0,0 +1,16 @@ +import { describe, expect, test } from 'vitest' +import { safeEncodeURIComponent } from '../../src' + +describe('safeEncodeURIComponent()', () => { + test('エンコードされた値が返ってくる', () => { + expect(safeEncodeURIComponent('?x=test')).toEqual({ data: '%3Fx%3Dtest', error: null }) + expect(safeEncodeURIComponent('foo bar')).toEqual({ data: 'foo%20bar', error: null }) + expect(safeEncodeURIComponent('テスト')).toEqual({ data: '%E3%83%86%E3%82%B9%E3%83%88', error: null }) + }) + + test('URIErrorが返ってくる', () => { + const { data, error } = safeEncodeURIComponent('\uD800') + expect(data).toBeNull() + expect(error).toBeInstanceOf(URIError) + }) +}) diff --git a/packages/utils/tests/functions/safeJsonParse.spec.ts b/packages/utils/tests/functions/safeJsonParse.spec.ts new file mode 100644 index 0000000..9173d95 --- /dev/null +++ b/packages/utils/tests/functions/safeJsonParse.spec.ts @@ -0,0 +1,34 @@ +import { describe, expect, test } from 'vitest' +import { safeJsonParse } from '../../src' + +describe('safeJsonParse()', () => { + describe('パースに成功する', () => { + test('optionsなし', () => { + const jsonString = '{"foo": "bar"}' + const { data, error } = safeJsonParse<{ foo: string }>(jsonString) + expect(data).toEqual({ foo: 'bar' }) + expect(error).toBeNull() + }) + + test('options.reviverあり', () => { + const jsonString = '{"foo": "bar"}' + const { data, error } = safeJsonParse<{ foo: string }>(jsonString, { + reviver: (key, value) => { + if (key === 'foo') { + return `${value}!` + } + return value + }, + }) + expect(data).toEqual({ foo: 'bar!' }) + expect(error).toBeNull() + }) + }) + + test('パースに失敗する', () => { + const jsonString = '{"foo": "bar"' + const { data, error } = safeJsonParse(jsonString) + expect(data).toBeNull() + expect(error).toBeInstanceOf(SyntaxError) + }) +}) diff --git a/packages/utils/tests/functions/safeJsonStringify.spec.ts b/packages/utils/tests/functions/safeJsonStringify.spec.ts new file mode 100644 index 0000000..41db837 --- /dev/null +++ b/packages/utils/tests/functions/safeJsonStringify.spec.ts @@ -0,0 +1,65 @@ +import { describe, expect, test } from 'vitest' +import { safeJsonStringify } from '../../src' + +describe('safeJsonStringify()', () => { + describe('文字列化に成功する', () => { + test('optionsなし', () => { + const { data, error } = safeJsonStringify({ foo: 'bar' }) + expect(data).toBe('{"foo":"bar"}') + expect(error).toBeNull() + }) + + test('options.replacerあり (関数のケース)', () => { + const target = { foo: 'bar', hoo: 3, goo: true } + const { data, error } = safeJsonStringify(target, { + // @ts-ignore: 問題ないので型エラーを無視 + replacer: (key: keyof typeof target, value: (typeof target)[keyof typeof target]) => { + if (key === 'foo') { + return `${value}!` + } + if (key === 'hoo' && typeof value === 'number') { + return value * 2 + } + return value + }, + }) + expect(data).toBe('{"foo":"bar!","hoo":6,"goo":true}') + expect(error).toBeNull() + }) + + test('options.replacerあり (配列のケース)', () => { + const target = { foo: 'bar', hoo: 3, goo: true, 3: 'three' } + const { data, error } = safeJsonStringify(target, { + replacer: ['foo', 'hoo', 3], + }) + expect(data).toBe('{"foo":"bar","hoo":3,"3":"three"}') + expect(error).toBeNull() + }) + + test('options.spaceあり (数値のケース)', () => { + const target = { foo: 'bar' } + const { data, error } = safeJsonStringify(target, { + space: 2, + }) + expect(data).toBe('{\n "foo": "bar"\n}') + expect(error).toBeNull() + }) + + test('options.spaceあり (文字のケース)', () => { + const target = { foo: 'bar' } + const { data, error } = safeJsonStringify(target, { + space: '\t', + }) + expect(data).toBe('{\n\t"foo": "bar"\n}') + expect(error).toBeNull() + }) + }) + + test('文字列化に失敗する', () => { + // BigInt は JSON.stringify で文字列化できないので例外が発生する + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#exceptions + const { data, error } = safeJsonStringify({ bigint: 2n }) + expect(data).toBeNull() + expect(error).toBeInstanceOf(TypeError) + }) +}) diff --git a/packages/utils/tests/types/utils.spec.ts b/packages/utils/tests/types/utils.spec.ts index ac46a01..82ab831 100644 --- a/packages/utils/tests/types/utils.spec.ts +++ b/packages/utils/tests/types/utils.spec.ts @@ -1,9 +1,10 @@ -import { expectTypeOf, describe, test } from 'vitest' +import { describe, expectTypeOf, test } from 'vitest' import type { - MatchTypeKeys, ExactMatchTypeKeys, - NotMatchTypeKeys, ExactNotMatchTypeKeys, + MatchTypeKeys, + NonNullishFields, + NotMatchTypeKeys, RequiredAtLeastOne, } from '../../src' @@ -113,4 +114,26 @@ describe('types/utils.ts', () => { expectTypeOf({}).not.toEqualTypeOf() }) }) + + test('NonNullishFields', () => { + expectTypeOf< + NonNullishFields<{ + id: `post_${number}` + title: string + body: string | undefined + author: { name: string; age: number | undefined } + createdAt: Date + updatedAt?: Date | null + }> + >().toEqualTypeOf<{ + id: `post_${number}` + title: string + body: string + author: { name: string; age: number | undefined } + createdAt: Date + updatedAt: Date + }>() + + expectTypeOf>().toEqualTypeOf() + }) }) diff --git a/website/packages/utils/functions/getHashFragment.md b/website/packages/utils/functions/getHashFragment.md index 2191ff4..be1f430 100644 --- a/website/packages/utils/functions/getHashFragment.md +++ b/website/packages/utils/functions/getHashFragment.md @@ -7,24 +7,28 @@ custom_edit_url: null **getHashFragment**(`url`): `string` -引数urlにあるフラグメントを削除したものを返却 +引数 url にあるフラグメントを削除したものを返却 ※ 文字列中に含まれる `+` (プラス記号)は半角スペースに変換されます +**`Throws`** + +内部で利用している `decodeURIComponent()` がエラーをスローする可能性がある + **`Example`** ```ts // 返値: hash fragment -getHashFragment('https://localhost:8080?test=32#hash+fragment') +getHashFragment("https://localhost:8080?test=32#hash+fragment"); // 返値: テスト -getHashFragment('https://localhost:8080?test=32#%E3%83%86%E3%82%B9%E3%83%88') +getHashFragment("https://localhost:8080?test=32#%E3%83%86%E3%82%B9%E3%83%88"); ``` ## Parameters -| Name | Type | -| :------ | :------ | +| Name | Type | +| :---- | :---------------- | | `url` | `string` \| `URL` | ## Returns diff --git a/website/packages/utils/functions/getQueryString.md b/website/packages/utils/functions/getQueryString.md index 5db823d..d6c3845 100644 --- a/website/packages/utils/functions/getQueryString.md +++ b/website/packages/utils/functions/getQueryString.md @@ -7,27 +7,31 @@ custom_edit_url: null **getQueryString**(`url`): `string` -引数urlのクエリパラメータ部分を返却 +引数 url のクエリパラメータ部分を返却 ※ 文字列中に含まれる `+` (プラス記号)は半角スペースに変換されます +**`Throws`** + +内部で利用している `decodeURIComponent()` がエラーをスローする可能性がある + **`Example`** ```ts // 返値: ?test1=32&test2=ア -getQueryString('https://localhost:8080?test1=32&test2=%E3%82%A2#fragment') +getQueryString("https://localhost:8080?test1=32&test2=%E3%82%A2#fragment"); // 返値: ?test1=32&test2=ア -getQueryString('/path/to/?test1=32&test2=%E3%82%A2#fragment') +getQueryString("/path/to/?test1=32&test2=%E3%82%A2#fragment"); // 返値: ?test1=3 2&test2=ア -getQueryString('https://localhost:8080?test1=3+2&test2=%E3%82%A2#fragment') +getQueryString("https://localhost:8080?test1=3+2&test2=%E3%82%A2#fragment"); ``` ## Parameters -| Name | Type | -| :------ | :------ | +| Name | Type | +| :---- | :------- | | `url` | `string` | ## Returns diff --git a/website/packages/utils/functions/safeDecodeURIComponent.md b/website/packages/utils/functions/safeDecodeURIComponent.md new file mode 100644 index 0000000..c263a66 --- /dev/null +++ b/website/packages/utils/functions/safeDecodeURIComponent.md @@ -0,0 +1,31 @@ +--- +id: "safe-decode-uri-component" +title: "safeDecodeURIComponent" +sidebar_label: "safeDecodeURIComponent" +custom_edit_url: null +--- + +**safeDecodeURIComponent**(`value`): \{ `data`: `string` ; `error`: `null` } \| \{ `data`: `null` ; `error`: `URIError` } + +decodeURIComponent()で発生する例外をキャッチして、例外が発生した場合はエラーオブジェクトを返却する + +**`Example`** + +```ts +const { data, error } = safeDecodeURIComponent("foo%20bar"); // => { data: 'foo bar', error: null } +if (error) { + console.error(error); +} else { + console.log(data); // => 'foo bar' +} +``` + +## Parameters + +| Name | Type | +| :------ | :------- | +| `value` | `string` | + +## Returns + +\{ `data`: `string` ; `error`: `null` } \| \{ `data`: `null` ; `error`: `URIError` } diff --git a/website/packages/utils/functions/safeEncodeURIComponent.md b/website/packages/utils/functions/safeEncodeURIComponent.md new file mode 100644 index 0000000..3e3a29b --- /dev/null +++ b/website/packages/utils/functions/safeEncodeURIComponent.md @@ -0,0 +1,31 @@ +--- +id: "safe-encode-uri-component" +title: "safeEncodeURIComponent" +sidebar_label: "safeEncodeURIComponent" +custom_edit_url: null +--- + +**safeEncodeURIComponent**(`value`): \{ `data`: `string` ; `error`: `null` } \| \{ `data`: `null` ; `error`: `URIError` } + +encodeURIComponent()で発生する例外をキャッチして、例外が発生した場合はエラーオブジェクトを返却する + +**`Example`** + +```ts +const { data, error } = safeEncodeURIComponent("foo bar"); // => { data: 'foo%20bar', error: null } +if (error) { + console.error(error); +} else { + console.log(data); // => 'foo%20bar' +} +``` + +## Parameters + +| Name | Type | +| :------ | :------- | +| `value` | `string` | + +## Returns + +\{ `data`: `string` ; `error`: `null` } \| \{ `data`: `null` ; `error`: `URIError` } diff --git a/website/packages/utils/functions/safeJsonParse.md b/website/packages/utils/functions/safeJsonParse.md new file mode 100644 index 0000000..3829385 --- /dev/null +++ b/website/packages/utils/functions/safeJsonParse.md @@ -0,0 +1,39 @@ +--- +id: "safe-json-parse" +title: "safeJsonParse" +sidebar_label: "safeJsonParse" +custom_edit_url: null +--- + +**safeJsonParse**\<`T`\>(`value`, `options?`): \{ `data`: `T` ; `error`: `null` } \| \{ `data`: `null` ; `error`: `SyntaxError` } + +JSON.parse()で発生する例外をキャッチして、例外が発生した場合はエラーオブジェクトを返す + +型変数 `T` は JSON.parse()でパースするデータの型を指定する + +※ ただし、型ガードは行わないため、呼び出し元で型ガードを適宜実施すること + +**`Example`** + +```ts +const { data, error } = safeJsonParse<{ foo: string }>('{"foo": "bar"}'); // => { data: { foo: 'bar' }, error: null } +if (error) { + console.error(error); +} else { + console.log(data); // => { foo: 'bar' } +} +``` + +## Parameters + +| Name | Type | +| :----------------- | :------- | +| `value` | `string` | +| `options?` | `Object` | +| `options.reviver?` | _※1_ | + +- _※1_ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#reviver に従う + +## Returns + +\{ `data`: `T` ; `error`: `null` } \| \{ `data`: `null` ; `error`: `SyntaxError` } diff --git a/website/packages/utils/functions/safeJsonStringify.md b/website/packages/utils/functions/safeJsonStringify.md new file mode 100644 index 0000000..4259d46 --- /dev/null +++ b/website/packages/utils/functions/safeJsonStringify.md @@ -0,0 +1,37 @@ +--- +id: "safe-json-stringify" +title: "safeJsonStringify" +sidebar_label: "safeJsonStringify" +custom_edit_url: null +--- + +**safeJsonStringify**\<`T`\>(`value`, `options?`): \{ `data`: `string` ; `error`: `null` } \| \{ `data`: `null` ; `error`: `TypeError` } + +JSON.stringify()で発生する例外をキャッチして、例外が発生した場合はエラーオブジェクトを返す + +**`Example`** + +```ts +const { data, error } = safeJsonStringify({ foo: "bar" }); // => { data: '{"foo":"bar"}', error: null } +if (error) { + console.error(error); +} else { + console.log(data); // => '{"foo":"bar"}' +} +``` + +## Parameters + +| Name | Type | +| :------------------ | :------- | +| `value` | `T` | +| `options?` | `Object` | +| `options.replacer?` | _※1_ | +| `options.space?` | _※2_ | + +- _※1_ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#replacer に従う +- _※2_ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#space に従う + +## Returns + +\{ `data`: `T` ; `error`: `null` } \| \{ `data`: `null` ; `error`: `SyntaxError` } diff --git a/website/packages/utils/types/NonNullishFields.md b/website/packages/utils/types/NonNullishFields.md new file mode 100644 index 0000000..b579c91 --- /dev/null +++ b/website/packages/utils/types/NonNullishFields.md @@ -0,0 +1,25 @@ +--- +id: "non-nullish-fields" +title: "NonNullishFields" +sidebar_label: "NonNullishFields" +custom_edit_url: null +--- + +オブジェクトの全フィールドの型から undefined,null を除外した型を得る + +※ ネストしたオブジェクトのフィールドに対しては適用されない + +**`Example`** + +```ts +type Post = { + id: `post_${number}`; + title: string; + body: string | undefined; + author: { name: string; age: number | undefined }; + createdAt: Date; + updatedAt?: Date | null; +}; +// NewPost => { id: `post_${number}`; title: string; body: string; author: { name: string; age: number | undefined }; createdAt: Date; updatedAt: Date } +type NewPost = NonNullishFields; +```