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

Result: no type guard function default implementation for the case to hydrate serialized raw json value #2204

Open
tetsuharuohzeki opened this issue Apr 4, 2024 · 3 comments

Comments

@tetsuharuohzeki
Copy link
Contributor

Motivation

Basically, we don't recommend to use our Result type in ser/de format directly.

We recommend:

  1. Use some framework library hide them in their magical veil.
  2. Intoduce some scheme and ser/de specific mechanism and you should write a layer to recover from a deserialized value and bridge to more "solid" typing world.

However, especially in web frontend or other small scripts, you sometimes do not setup data exchange specific type & format, and use serializable value directly, via JSON.stringify and JSON.parse ugh.

For example, implement "hydration" mechanism by self without taking a framework. To build a their ones for their application.

In such case, as poor man's design (or skip overhead in hydration steps), they want to do minimum value runtime type checking as type guard without any other existing serialize protocol. So they just implement their own data exchange protocol!

This issue discuss about that a type guard function which we should as default (or should not do).

@tetsuharuohzeki
Copy link
Contributor Author

Basically, my answer is "don't do it, introduce a specific some data ex change format or type scheme".

@tetsuharuohzeki
Copy link
Contributor Author

Of course, "no check" is one of a approach. It depends on system design decision.

@tetsuharuohzeki
Copy link
Contributor Author

This an example to type guard function for PlainResult/Result.
But we already have a some discussion points:

  1. How level do you check an actual object deeply? The following code is just returns Result<unknown, unknown>, but it useless. This shows more additional checks to get more concrete type.
  2. Which version of this package do you assume about a value? option-t/PlainResult/Result has a bit legacy variants (e.g. Todays' result.val === null if it's created by createOk(). But some legacy version would be result.val === undefined).
  3. Should we change the Result type definition for them purpose? As a part of code cleanup, I would like to make Result type more simply but it might break a backward compatibility of types. It would be problematic for large scale codebase mixing a multiple versions of libaries and many versions of option-t also lives. For them, we need to investigate a way to avoid to break a backward compatibility.
import type { Result } from './result.js';

function hasProp<K extends PropertyKey>(data: object, prop: K): data is Record<K, unknown> {
    return prop in data;
}

export function isResultType(value: unknown): value is Result<unknown, unknown> {
    if (typeof value !== 'object') {
        return false;
    }

    if (!value) {
        return false;
    }

    if (!hasProp(value, 'ok')) {
        return false;
    }

    if (typeof value.ok !== 'boolean') {
        return false;
    }

    if (value.ok) {
        if (!hasProp(value, 'val')) {
            return false;
        }
    } else if (!hasProp(value, 'err')) {
        return false;
    }

    return true;
}
``

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant