Hacker News new | ask | show | jobs
by 9034725985 1197 days ago
> With the ‘unknown’ type available is there a good case for ‘any’ anymore?

Lets say you have some input json that you want to slightly modify to something else. How would you do this with unknown? I can't just blindly replace any with unknown. I'd get errors like this: The right-hand side of a 'for...in' statement must be of type 'any', an object type or a type parameter, but here has type 'unknown'.ts(2407) For example, how can I do this better?

Remember the input json could be pretty much anything. I don't have a spec other than I only care about things that end with __c.

https://github.com/kusl/salesforcecontactmapper/blob/eff0b3e...

    import { Output } from "./Output";
    import { Preference } from "./Preference";

    export function MyMap(input: unknown): Output {
        const mypreferences = Array<Preference>();
        for (const prefCode in input) {
            if (prefCode.endsWith("__c")) {
                if (prefCode === "IsInternalUpdate__c") {
                    continue;
                }
                let currentValue = "";
                if (input[prefCode] !== null) {
                    currentValue = input[prefCode].toString();
                }
                if (currentValue === "true") {
                    currentValue = "True";
                }
                if (currentValue === "false") {
                    currentValue = "False";
                }
                const preference: Preference = {
                    PrefCode: prefCode,
                    CurrentValue: currentValue
                }
                mypreferences.push(preference);
            }
        }
        const myOutput: Output = {
            ContactId: input.Contact__c,
            Email: input.ContactEmail__c,
            IsInternalUpdate: true,
            Preferences: mypreferences
        }
        return myOutput;
    }
3 comments

well you expect 'input' to be something that you can iterate over, so clearly using any is wrong here.
yes, input is a json of some kind.

You could say technically could be simply { "Unsubscribe__c": false } or even {} both of which are silly in my case because there is no key for me to identify who the person is but they are valid inputs.

Or the test case I have is https://github.com/kusl/salesforcecontactmapper/blob/eff0b3e...

Or the input could have a thousand key values and I only care about some of them. What should my object look like? How do I create a class that says everything that ends in "__c" is something I care about? I tried unknown. I tried Object. How do I fix this (and learn something so I fix all future code I write)?

You can go incredibly far with the type system.

If you wanna go down that rabbit hole, I'd suggest Typescript type challenges. Completely blew my mind when I came across it the first time.

When you start out with typescript you might think Omit<> and Partial<> are cool but holy hell, you can do so much more.

    input: Record<string, unknown>
Thank you. That gives me a red underline under ContactId and Email now. I think because input.Contact__c and input.ContactEmail__c are unknown. I think this is the right direction. What is my next step?

    const myOutput: Output = {
        ContactId: input.Contact__c,
        Email: input.ContactEmail__c,
        IsInternalUpdate: true,
        Preferences: mypreferences
    }
(property) Output.ContactId: string Type 'unknown' is not assignable to type 'string'.ts(2322) Output.ts(4, 5): The expected type comes from property 'ContactId' which is declared here on type 'Output'
What's wrong with Object?
If I set input as Object,

    if (input[prefCode] !== null) {
        currentValue = input[prefCode].toString();
    }
in the lines above, I see a red underline under input[prefCode]

> Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Object'. No index signature with a parameter of type 'string' was found on type 'Object'.ts(7053)

Could you use a helper like

    function getProperty<T, K extends keyof T>(o: T, propertyName: K): T[K] {
        return o[propertyName];
    }

?
You can do some pretty powerful stuff with TypeScript types, so you could model it like this: https://www.typescriptlang.org/play?#code/C4TwDgpgBAysBOBLAd...
Nice I tbink that is the answer! It is for when the way you need to deal with the data is so dynamic and runtime specified that crafting out the interface/types to cast to would be painful to impossible. Data wrangling.