From 43fab81819ee2612ff2a6b9129a101c8a7aeb1c6 Mon Sep 17 00:00:00 2001 From: Olgierd Kasprowicz Date: Sat, 16 May 2020 17:33:33 +0200 Subject: [PATCH] Approach Resource typing differently in the UI (#58) Previously the Resource typing was awkward at best - asserting Resources to concrete types seamed like needles work that defied the point of having them defined as interfaces One potential solution was asserting string literal to string literal, but that felt backwards, example: "literal" as "literal" Someone in the Github thread[0] suggested asserting them in the following manner: "literal" as const - which is a bit better, but still misses the point Due to technical reasons the literal inferred type was string, rather than the literal itself. What seams to solve the problem is asserting the whole object to be a Resource. That also solves the problem with creeping import scope while at the same time setting up correct guards at compile time Last, but not least I think that the documentation on type assertion is misleading at best (couldn't find an example describing the mechanism and didn't feel like going through the source) - the mechanism is much more safe than described in the official docs, which cover the case of any -> T. Whereas in the more general case of T -> U assertion the overlap is checked (so that if I make a typo in the object an error is raised) [0] https://github.com/microsoft/TypeScript/issues/25889 --- src/App.tsx | 7 +++---- src/ResourceAdder.tsx | 8 +++----- src/ResourceEditor.tsx | 2 +- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 1977e34..b0dc359 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -27,8 +27,8 @@ export default class App extends Component<{ { super(props); - // TODO: get rid of the casting - const ourTree = makeTree({__typename: "Text", content: "korzen", is_done: false} as Text); + const initial_resource: Resource = {__typename: "Text", content: "korzen", is_done: false}; + const ourTree = makeTree(initial_resource); this.state= { chosenNode: ourTree.root.id, @@ -206,11 +206,10 @@ function displayTree(t: Tree, chosenNode: NodeID): ReactTreeGraphNode } -// TODO: get rid of the casting function displayResource(r: Resource): string { return { - "Link": (r as unknown as Link).address, + "Link": (r as Link).address, "Text": (r as Text).content, }[r.__typename]; } diff --git a/src/ResourceAdder.tsx b/src/ResourceAdder.tsx index c5197c6..a1b0492 100644 --- a/src/ResourceAdder.tsx +++ b/src/ResourceAdder.tsx @@ -1,5 +1,4 @@ -// TODO: how to limit importing scope? -import { Resource, ResourceTypeString, ResourceTypeStringValues, Link, Text } from "./core/resources"; +import { Resource, ResourceTypeString, ResourceTypeStringValues } from "./core/resources"; import React, { FunctionComponent } from "react"; import { Formik, Form, Field } from "formik"; @@ -40,11 +39,10 @@ const ResourceAdder: React.FunctionComponent<{ export default ResourceAdder; -// TODO: get rid of the casting function default_for_typestring(t: ResourceTypeString): Resource { return { - "Link": { __typename: "Link", address: "", is_done: false } as Link, - "Text": { __typename: "Text", content: "", is_done: false } as Text, + "Link": { __typename: "Link", address: "", is_done: false } as Resource, + "Text": { __typename: "Text", content: "", is_done: false } as Resource, }[t]; } diff --git a/src/ResourceEditor.tsx b/src/ResourceEditor.tsx index ade5347..de16773 100644 --- a/src/ResourceEditor.tsx +++ b/src/ResourceEditor.tsx @@ -27,7 +27,7 @@ const ResourceEditor: React.FunctionComponent<{ __typename: props.resource.__typename, }; - props.onEditonCommit(resource as any); + props.onEditonCommit(resource as Resource); }} > {