TylorS / typed-unmaintained

The TypeScript Standard Library
MIT License
121 stars 7 forks source link

Learning resources #40

Open MattMcFarland opened 6 years ago

MattMcFarland commented 6 years ago

Do you have a blog post that shows how one would use your libraries? I was thinking of using a Maybe for a situation where I was originally using a ternary expression that returned an object or undefined. I think this might be a good candidate. I'm really trying to refactor some of my code to be more functional, and any resources you have may be of great help.

Thanks again for making such an awesome suite of libraries, I cant wait to share this with some of my friends! 👍

TylorS commented 6 years ago

Hey Matt, there is no additional documentation at this time. I'd love to see us develop these sorts of tutorials in our wiki. What kinds of things would you like to see explained in more depth?

Your use case sounds like a great use of Maybe. Do you have any particular questions about them now that I could try to help you with?

I'm glad you're enjoying the libraries. They're stable and used in a production environments.

MattMcFarland commented 6 years ago

@TylorS Thanks for the reply. To give you some context, I'm currently working on an AST Parser, and because ASTs are deeply nested structures, I think FP could be a great candidate for working with finding the various types in the AST.

I've been finding myself constantly checking types really, and I am wanting the code to be clean, concise, and predictable, and with all this checking, procedure, iteration, things can get unwieldy pretty fast. I'm pretty new to typescript, but loving the type safety, and really want to try to use more functional types as well since I'm using types and all!

So just to give you a small taste, here is a small amount of some functions I have written to type check of whether or not this is a NodePath, or Node, and then what kind of Node it is:

export function isPath(prop: PathOrNode): prop is NodePath {
  return prop instanceof NodePath;
}

export function isNode(prop: PathOrNode): prop is Node {
  return (prop as Node).start !== undefined;
}

export function getVariableId(prop: PathOrNode): string | void {
  if (isPath(prop)) return getVariableIdFromPath(prop);
  if (isNode(prop)) return getVariableIdFromNode(prop);
}

export function getVariableIdFromNode(node: Node): string {
  if (isVariableDeclarator(node) && isIdentifier(node.id))
    return getIdentifierName(node.id);
}

export function getIdentifierName(node: Identifier) {
  if (isNamedIdentifier(node)) return node.name;
}

export function getIdNameFromPath(path: NodePath<Identifier>): string {
  return getIdentifierName(path.node);
}

export function getVariableIdFromPath(path: NodePath<Node>): string {
  return getVariableIdFromNode(path.node);
}

export function isNamedIdentifier(node: Node): node is INamedIdentifier {
  return isIdentifier(node) && node.name !== undefined;
}

The cool thing is, I have a lot of types to work with thanks to Babylon's team writing awesome typescript definitions. AS you see up there, this is just for getting <Identifier>, I have a lot more code (I wont dump it all here) and there has to be around 100 or so different types that pass into NodePath<T> and that extend Node

I've been spending an immense amount of time on this project, (near 100 hours) and really I find myself constantly refactoring how I'm resolving these node types because I keep thinking there has to be a cleaner and more concise way...

I did try to use Ramda, and am playing around with your awesome libraries, but am struggling just figuring out how to get started!

The project I'm working on is a document generator for ES6, flowtype, and typescript. I want it to be different then other document generators, meaning it will infer the documentation from the AST instead of looking for jsdoc tags.. Its a work in progress for sure, you can see how crazy things are getting already over at https://github.com/MattMcFarland/docsense

TylorS commented 6 years ago

Wow, what a cool project! I've been thinking of building something pretty much identical to docsense 👍

If you are familiar with Ramda a lot of our APIs are the same or very similar, in particular @typed/list shares a lot of functions with Ramda. The biggest difference is we use a couple of data structures throughout the codebase like Maybe and Either. For example our implementation of findIndex returns a Maybe<Index>. So rather than using -1 to signal "not found", Nothing would be the indicator of the same state. However with a Maybe you can still continue to call functions like map and perform other operations. If the Maybe is in a Nothing state no work is ever actually performed and only when you absolutely need the value do you need a function like fromMaybe which can be a clean way to provide fallback values you'd generally require an if statement or a ternary.

Just going with findIndex I'll try to come up with a small example usage of Maybe

// without typed
function replaceChildById<A extends { id: string }>(newValue: A, values: Array<A>): Array<A> {
  const { id } = newValue

  // Try to find index by id
  const index = values.findIndex(value => value.id === id)

  // If the value can not be found return the original array
  if (index === -1)
    return values

  // immutably replace the old value 
  const newValues = values.slice()
  newValues[index] = newValue

  return newValues
}

// with typed
import { pipe, partial, __ } from '@typed/functions'
import { propEq } from '@typed/logic'
import { findIndex, update } from '@typed/list'
import { map, fromMaybe } from '@typed/maybe'

function replaceChildById<A extends { id: string }>(newValue: A, values: Array<A>): Array<A> {
  const { id } = newValue
  return pipe<Array<A>, Array<A>>(
    findIndex(propEq('id', id)), // find the index by id
    map(partial(update, [__, newValue, values])), // immutably replace old value
    fromMaybe(values) // default to returning original values
  )(values)
}

I hope this helps at least a little bit!

prodrammer commented 5 years ago

@MattMcFarland needs documentation for typed to continue his documentation generation project, which, once complete, @TylorS can use to generate documentation for typed.