dohomi / storyblok-generate-ts

Generates TypeScript interface types based on Storyblok component file
MIT License
102 stars 33 forks source link

Why does MultilinkStoryblok provide `linktype?: string` #38

Closed wweaver closed 1 year ago

wweaver commented 1 year ago

For me using the MultilinkStoryblok is hard to use because there's no way to get out of this type because linktype blankets all strings

  | {
      cached_url?: string;
      linktype?: string;
      [k: string]: any;
    }

https://github.com/dohomi/storyblok-generate-ts/blob/45fa291327cf6e3925dd985eda5fad6cae2c9408/example/component-types-sb-backup.d.ts#L256-L278

I would want to be able to do something like this

if (blok.linktype === 'url') {
    return blok.url;
}

But it says url is any because the base type is also matched

Cursor_and_frontend_–_helpers_ts

wweaver commented 1 year ago

Thanks for this project btw. I was just introduced to it today and was trying to resolve an issue with having to do as in a bunch of places. Is it just that the object isn't fully fleshed out with all options and wanted to have a fallback for object types that aren't currently spelled out?

dohomi commented 1 year ago

@wweaver do you have any code example?

wweaver commented 1 year ago

@dohomi, nothing publicly available. The code example I have is what I shared. I can try to create a dummy project in the near future that shows it.

dohomi commented 1 year ago

mostly blok.cache_url is in use - if thats not set then it would fallback to blok.email or blok.url. This is not really possible to get right via the json typescript converter, it was more like try and error on my side and some community contributions

dohomi commented 1 year ago

you can also disable the unknown any feature flag: https://github.com/dohomi/storyblok-generate-ts#example thats removing all [k:string]:any statements

wweaver commented 1 year ago

you can also disable the unknown any feature flag: https://github.com/dohomi/storyblok-generate-ts#example thats removing all [k:string]:any statements

Funny, the other devs had that enabled, then I turned it off because there were type errors when trying to use storyblok-js-client. The team had to do storyblokEditable(blok as unknown as SbBlokData)}. While I'm really one that's against any I feel like unknown makes it harder to work with in this case within typescript. I would rather just not have [k:string]:any or [k:string]:unknown at all. But again I don't know the storyblok API at all to know what ramifications that would have.

Edit: The reason for not having it at all is that I want to know explicitly what's there. If there's something I need that's not defined in the schema then there's something that needs to be updated with the schema. Making any key available I think violates the idea of typescript in some ways. There are exceptions to that rule, but if we're trying to build out the structure of the response I don't think we need to allow any key.

dohomi commented 1 year ago

Ideally Storyblok should enable type generation based on space ID's components. I just started this repo due to missing types when building my component API.

wweaver commented 1 year ago

Ideally Storyblok should enable type generation based on space ID's components. I just started this repo due to missing types when building my component API.

Thanks @dohomi. I just sent an email to our representative at storyblok with the concerns as they mentioned they are using your library for stuff they are building internally. Unfortunately I can't post it all here because it had some details in our code.

But the gist I had was this:

  1. The biggest concern I had was that the types are all generated with a generic [key: string]: any (or [key: string]: unknown]) which to me makes these types hard to work with.
  2. Another concern I had was with the MultilinkStoryblok defining a catchall type for linktype?: string which makes it much harder to narrow down the type you’re actually working with.

I also mentioned that having types like this would be beneficial

export interface Story {
    name: string;
    created_at?: string;
    published_at?: string;
    id: number;
    uuid: string;
    content?: {
        [k: string]: any;
    };
    slug: string;
    full_slug: string;
    sort_by_date?: null | string;
    position?: number;
    tag_list?: string[];
    is_startpage?: boolean;
    parent_id?: null | number;
    meta_data?: null | {
        [k: string]: any;
    };
    group_id?: string;
    first_published_at?: string;
    release_id?: null | number;
    lang?: string;
    path?: null | string;
    alternates?: any[];
    default_full_slug?: null | string;
    translated_slugs?: null | any[];
}

export interface LinkStoryStoryblok {
    id?: string;
    cached_url?: string;
    anchor?: string;
    linktype?: 'story';
    story?: Story;
}

export interface LinkAssetStoryblok {
    url?: string;
    cached_url?: string;
    anchor?: string;
    linktype?: 'asset';
}

export interface LinkUrlStoryblok {
    url?: string;
    cached_url?: string;
    anchor?: string;
    linktype?: 'url';
}

export interface LinkEmailStoryblok {
    email?: string;
    linktype?: 'email';
}

export type MultilinkStoryblok = LinkStoryStoryblok | LinkAssetStoryblok | LinkUrlStoryblok | LinkEmailStoryblok;

With all story types being generated extending the Story

export interface CustomStoryStoryblok extends Story {
    _uid: string;
    component: 'custom-story';
    ...
}
wweaver commented 1 year ago

Looking through your code and I do see you have a StoryBlokStory<TContent> interface that is the Story interface I mentioned, so that would work nicely I'd think.

wweaver commented 1 year ago

you can also disable the unknown any feature flag: https://github.com/dohomi/storyblok-generate-ts#example thats removing all [k:string]:any statements

I see you can remove it with compilerOptions.additionalProperties=false.

dohomi commented 1 year ago

you can read more about the compiler option in the parent repo which runs this plugin https://github.com/bcherny/json-schema-to-typescript#options

you can extend your schema to customise everything you need, I for example need to add relations and use it in the following way: https://github.com/dohomi/storyblok-generate-ts#resolve-relations